Skip to content

fix(blocknode): honor --values plugins.names via "no override" preset#799

Open
alex-au wants to merge 1 commit into
mainfrom
00731-block-node-plugins-names-from-values
Open

fix(blocknode): honor --values plugins.names via "no override" preset#799
alex-au wants to merge 1 commit into
mainfrom
00731-block-node-plugins-names-from-values

Conversation

@alex-au

@alex-au alex-au commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Description

A block-node --values file that sets plugins.names was silently ignored on an
interactive install. The plugin-preset prompt always pre-selected a preset (default
tier1-lfh) and offered no "use my values file" option, so the resolved plugin list was
never empty — and injectPluginsConfig then overwrote the values-file plugins.names
after the deep-merge (PR #703) had correctly let it win. Operators who set plugins.names
in --values got the preset bundle deployed instead, a silent divergence between intent
and what actually ran.

This PR implements the precedence flags/TUI (explicit) > values.yaml > chart default
by letting the resolution produce an empty plugin list when the operator did not
explicitly choose plugins. An empty list already makes injectPluginsConfig a no-op, so
the merged values-file (or chart-default) plugins.names survives untouched.
injectPluginsConfig and mergeValues are unchanged.

Files changed

File Change
internal/blocknode/blocknode_plugins.go Add PresetNone = "none" + label + menu entry; deliberately not in any Presets map → IsKnownPreset("none")=false, resolves to ""
internal/blocknode/values.go Add exported ValuesFileDefinesPlugins(path) (error-tolerant; scalar or YAML-sequence plugins.names)
internal/ui/prompt/blocknode.go RunPluginPresetPrompts gains a valuesFile param; smart-defaults to PresetNone when the file defines plugins.names
cmd/cli/commands/block/node/init.go Pass flagValuesFile to the prompt; upgrade re-resolve guard now && !ValuesFileDefinesPlugins(...)
pkg/models/inputs.go, cmd/cli/commands/common/flags_blocknode.go, docs/quickstart.md Document none on PluginPreset / the --plugin-preset flag
internal/blocknode/blocknode_plugins_test.go Tests for the PresetNone registry contract and ValuesFileDefinesPlugins

Behavior

  • Interactive install with -f defining plugins.names → prompt now lists and
    pre-selects
    "Use Values File / Chart Default"; accepting it deploys the file's list.
  • --plugins / --plugin-preset still suppress the prompt and win (flags beat the file).
  • --plugin-preset none is a valid scripted "no override" value.
  • No -f plugins / no explicit choice → unchanged (tier1-lfh default; scripted → chart default).
  • upgrade: a values-managed plugins.names is no longer clobbered by the saved-state
    re-resolve, while the chart-version plugin rename still applies when plugins are not
    values-managed.

Review guide

Code-review checklist

  • PresetNone is absent from every blockNodePluginHistory[*].Presets map →
    IsKnownPreset("none")==false, PluginListForPreset("none",…)==""
    (internal/blocknode/blocknode_plugins.go).
  • Selecting PresetNone leaves *flagPlugins empty — the existing Pass-2
    != PresetCustom early return handles it (internal/ui/prompt/blocknode.go).
  • init.go resolution: PresetNonepluginList=="", so neither the
    --plugins required error nor the custom promotion triggers
    (cmd/cli/commands/block/node/init.go resolve block).
  • Upgrade guard skips the state re-resolve only when the values file defines
    plugins; otherwise the 0.35 s3-archive → cloud-storage-* rename still applies.
  • Smart default overrides the tier1-lfh/state default only when the values file
    actually defines plugins.names (common no--f case unchanged).
  • injectPluginsConfig / mergeValues untouched.

Test commands

# macOS-runnable unit tests (core of the fix)
go test ./internal/blocknode/... ./internal/ui/prompt/... ./pkg/models/...
go test ./internal/blocknode/ -run 'PresetNone|ValuesFileDefinesPlugins|AvailablePresets' -v

# Full suite incl. Linux-only packages — run in the UTM VM
task vm:test:unit
task vm:test:integration TEST_NAME='^Test.*Install.*$'

Manual UAT (VM) — verified end-to-end

  1. Create a values file with a plugin list distinct from every built-in preset — the
    full tier1-lfh list minus backfill:
    printf 'plugins:\n  names: "facility-messaging,block-access-service,health,server-status,stream-publisher,stream-subscriber,verification,blocks-file-historic,blocks-file-recent"\n' > /tmp/myvalues.yaml

    Note: a very sparse plugin set (e.g. just health,verification) can make the
    block-node server fail its /healthz/readyz probe and never come up, causing Helm's
    --atomic install to time out and roll back the whole release — a property of that
    plugin combination, not of this fix. Confirmed via kubectl get events -n <ns>:
    the pod pulled the image and started, but block-node-server never opened its port
    in time. Use a fuller-but-still-custom list (as above) to get a stable release you
    can inspect with helm get values.

  2. Self-install the provisioner once, then run the interactive install (use the installed
    binary on PATH, not ./bin/...):
    sudo solo-provisioner install
    sudo solo-provisioner block node install -p local \
      --namespace bn --release-name bn --chart-version 0.37.0 \
      --base-path /opt/bn --historic-retention 0 --recent-retention 96000 \
      -f /tmp/myvalues.yaml
    (0.37.0 is the newest chart version published to ghcr.io/hiero-ledger/hiero-block-node
    at time of writing; pick whatever is current.)
  3. Expected — smart default: the "Block Node Plugin Preset" prompt now lists a fourth
    option and pre-selects it:
    ┃ Block Node Plugin Preset
    ┃   Tier 1 — Local Full History  (blocks stored on local disk)
    ┃   Tier 1 — Remote Full History  (blocks stored in cloud storage)
    ┃   Custom  (select individual plugins)
    ┃ > Use Values File / Chart Default  (no override)
    
  4. Accept "Use Values File / Chart Default". Confirm the values file won:
    helm get values bn -n bn -a | grep -A1 '^plugins:'
    # observed: names: facility-messaging,block-access-service,health,server-status,
    #   stream-publisher,stream-subscriber,verification,blocks-file-historic,blocks-file-recent
    # (9 plugins — NOT the 10-plugin tier1-lfh bundle, which also includes backfill)
  5. Flags still win: re-run adding --plugin-preset tier1-lfh (or --plugins a,b) — no
    prompt appears and the preset/flag list is deployed, overriding the file.
  6. Unchanged default: re-run with a -f file that has no plugins.names (or no
    -f) — the prompt defaults to Tier 1 — Local Full History as before.
  7. Scripted no-override: --force --plugin-preset none -f /tmp/myvalues.yaml deploys
    the file's plugins.names with no prompt.

Risks / rollback

Low. The interactive default only changes when the --values file defines plugins.names;
all other flows are unchanged, and injectPluginsConfig/mergeValues are untouched.
Rollback = revert the PresetNone additions, the prompt smart-default line, and the
upgrade-guard clause.

Stacking note

Builds on merged PR #703 (deep-merge custom --values over the embedded profile base),
which is what lets a values-file plugins.names survive the merge in the first place.

Related Issues

@alex-au alex-au requested a review from a team as a code owner July 2, 2026 14:49
@alex-au alex-au requested a review from crypto-pablo July 2, 2026 14:49
@swirlds-automation

swirlds-automation commented Jul 2, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@AlfredoG87 AlfredoG87 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes interactive block-node installs/upgrades where an operator-provided --values file setting plugins.names could be silently overridden by the TUI plugin preset selection. It introduces a “no override” preset (none) and a values-file probe so that (when plugins.names is managed via --values) the prompt defaults to not injecting a preset-derived plugin list, preserving Helm values precedence.

Changes:

  • Add a PresetNone = "none" option to the plugin preset prompt that resolves to an empty plugin list (so injectPluginsConfig becomes a no-op).
  • Add ValuesFileDefinesPlugins(path) and use it to smart-default the interactive preset to “none” when the --values file defines plugins.names, and to guard upgrade re-resolution from state.
  • Update CLI/docs/model comments and add unit tests for the new preset contract + values-file detection.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/models/inputs.go Document none as a “no override” plugin-preset value.
internal/ui/prompt/blocknode.go Add valuesFile param and smart-default preset to none when the values file defines plugins.names.
internal/blocknode/values.go Add ValuesFileDefinesPlugins helper used by prompt and upgrade guard.
internal/blocknode/blocknode_plugins.go Add PresetNone, label, and ordered menu entry; keep it out of preset maps so it resolves to empty list.
internal/blocknode/blocknode_plugins_test.go Add tests for PresetNone contract and ValuesFileDefinesPlugins.
cmd/cli/commands/block/node/init.go Pass --values path into prompt; skip upgrade re-resolve when values file defines plugins.
cmd/cli/commands/common/flags_blocknode.go Update --plugin-preset flag help text to include none.
docs/quickstart.md Document --plugin-preset none semantics in quickstart flags table.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/blocknode/values.go Outdated
Comment thread internal/blocknode/values.go
Comment thread internal/blocknode/blocknode_plugins_test.go
@alex-au alex-au force-pushed the 00731-block-node-plugins-names-from-values branch 4 times, most recently from a3b2ed2 to 34451eb Compare July 3, 2026 06:23
An interactive block-node install silently ignored a --values file that set
plugins.names: the TUI always pre-selected a preset (tier1-lfh) and offered no
"use my values file" option, so the resolved plugin list was never empty and
injectPluginsConfig overwrote the merged values-file list after the deep-merge.

Implement precedence flags/TUI (explicit) > values.yaml > chart default by
letting the resolution produce an empty plugin list when the operator did not
explicitly choose plugins:

- Add PresetNone ("none") that resolves to an empty list (deliberately not in
  any Presets map, so IsKnownPreset is false and PluginListForPreset returns "").
  An empty list makes injectPluginsConfig a no-op, so the merged
  values-file/chart-default plugins.names survives. Its TUI label reads
  "Use Values File / Chart Default  (no override)", matching the wording issue
  #731 itself proposes: outcome first (what gets deployed), mechanism second
  (no preset override) — avoiding "override" as the headline, which read as
  ambiguous (override by what, of what) during manual UAT.
- Smart-default the interactive prompt to PresetNone when the --values file
  defines plugins.names, so the file wins unless the operator picks a preset.
- Guard the non-interactive upgrade state re-resolve so it does not clobber a
  values-managed plugin list, while still applying the chart-version plugin
  rename (0.35 s3-archive -> cloud-storage-*) when plugins are not values-managed.

ValuesFileDefinesPlugins treats the plugins.names key as "values-managed" the
moment it is present, regardless of its value: an explicit empty string, empty
list, or null all count. This matters because Helm's chartutil.CoalesceTables
treats an operator-set null as an instruction to delete the chart's default
plugins.names entirely, which is just as deliberate an operator choice as
setting a concrete list and must not be overwritten by a preset-derived one.

injectPluginsConfig and mergeValues are unchanged. --plugin-preset none is also
a valid scripted "no override" value.

Closes #731

Signed-off-by: alex-au <alex.w.aus@gmail.com>
@alex-au alex-au force-pushed the 00731-block-node-plugins-names-from-values branch from 34451eb to a069145 Compare July 3, 2026 07:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Block-node plugins.names from --values is ignored; honor precedence flags/TUI > values.yaml > chart default

4 participants