Skip to content

fix(operator): hosting-deploy refuses a vault values half that carries structure (Memex#295) - #5700

Merged
meshweaver-cloud[bot] merged 1 commit into
mainfrom
fix/295-vault-structure-refuse
Sep 25, 2026
Merged

meshweaver-cloud[bot] merged 1 commit into
mainfrom
fix/295-vault-structure-refuse

Conversation

@rbuergi

@rbuergi rbuergi commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

What

hosting-deploy (the operator's Provision/Reconcile path) layers the Key Vault values half helm-values-<release> FIRST and the record's render LAST. It now reads the half's top-level key names (never a value) and refuses, before helm and naming them:

  • any key outside secrets, parameters, pgbackrest (the same allow-list the Memex lane's capture stores and its guard reads, scripts/vault-values.py VAULT_FAMILIES);
  • a half it cannot read as a mapping (block YAML, or a JSON object via jq);
  • a half with none of the families.

The refusal names the remedy: a governed HelmRelease action with helmAction: capture.

Why

On 2026-09-25 the V58 Reconcile of memex failed at helm upgrade: Job memex-migration-62 invalid: duplicate volume "kv-secrets". The half still carried legacy extraVolumes/extraVolumeMounts/extraEnvFrom. helm replaces a list the later file names and leaves one it omits. HelmValues.Render omits an empty list (the memex overlay writes extraVolumes: [], but the render writes no key), so the vault's list deployed beside the record's keyVaultSecretClasses wiring. A structural map merges instead, and silently supplies every leaf the render omits. This is C4 of Memex#295 on the operator path. The lane already has its own switch.

I did not change the render to emit []. With structure refused at the only earlier layer, an omitted list falls to the chart default, so there is nothing left to override. HelmValuesTests also asserts the no-legacy-lists shape on purpose.

Verified

  • deploy/aks/operator/test/run-tests.sh: 601 passed, 0 failed. The new cases cover: a structural list refused before helm and named, with no value echoed; a structural map; families-only accepted (quoted keys, comments); JSON accepted and refused; a top-level list refused as unreadable; a family-less half refused.
  • I ran the reader against both real halves, key names only. helm-values-memex gives pgbackrest secrets (passes, post-capture). helm-values-memexcloud gives 14 keys including config image ingress … (refused), which matches a PyYAML read of the same files. PyYAML's indentless sequences (- name: at column 0 under a key) are handled.

Rollout consequence

This takes effect when an operator image carrying it runs. From then on, memex-cloud's Reconcile refuses until its half is re-captured. The capture is safe: I measured it against a local HelmValues.Render of the live record, and every vault-only leaf is inert (image.* and ingress.tls.* are not read by the chart, and portal.image/migration.image are --set by this script). Doc: Architecture/DeploymentEnvLayers → "The half carries secret families only".

Pairs-with: none — no public C# surface is touched (bash operator script, its test, one doc page).

🤖 Generated with Claude Code

…rries structure (Memex#295)

The operator layers helm-values-<release> FIRST and the record's render LAST. helm replaces a list
the later file names and leaves one it omits, and HelmValues omits an empty list, so a legacy
extraVolumes/extraVolumeMounts/extraEnvFrom left in the half deployed beside the record's own
keyVaultSecretClasses wiring: the memex V58 Reconcile failed at helm upgrade with
"Job memex-migration-62 invalid: duplicate volume kv-secrets". A structural map merges instead and
silently supplies every leaf the render does not name.

hosting-deploy now reads only the half's top-level key NAMES and refuses, before helm and naming
them, any key outside secrets/parameters/pgbackrest (the allow-list the config repo's capture and
lane guard share), an unreadable half, and a half holding none of the families. The remedy it names
is a governed HelmRelease capture. Checked against both real halves (key names only): memex passes
(pgbackrest, secrets); memex-cloud is refused until it is re-captured.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 25, 2026 18:07

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.

Copilot review overview

🔵 Needs a closer look

Three moderate validation edge cases remain unresolved in hosting-deploy.

Review effort: Lite
Findings: None

What changed in this PR

Adds pre-Helm validation for Key Vault values halves, restricting them to approved secret families and documenting the recapture workflow.

Changes:

  • Added YAML/JSON structure and family validation.
  • Added regression tests for accepted and rejected formats.
  • Documented the values-half contract.
File Summary
src/​MeshWeaver.Documentation/​Data/​Architecture/​DeploymentEnvLayers.md Documents the values-half contract.
deploy/​aks/​operator/​test/​run-tests.sh Tests validation behavior and edge cases.
deploy/​aks/​operator/​bin/​hosting-deploy Validates vault values before Helm execution.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

456 tests  ±0   456 ✅ ±0   42s ⏱️ -19s
  3 suites ±0     0 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit 78b312f. ± Comparison against base commit 92006e8.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

  1 files  ±0    1 suites  ±0   3m 8s ⏱️ +31s
345 tests ±0  345 ✅ ±0  0 💤 ±0  0 ❌ ±0 
349 runs  ±0  349 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 78b312f. ± Comparison against base commit 92006e8.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

1 673 tests  ±0   1 673 ✅ ±0   3m 17s ⏱️ +4s
    2 suites ±0       0 💤 ±0 
    2 files   ±0       0 ❌ ±0 

Results for commit 78b312f. ± Comparison against base commit 92006e8.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

    3 files  ±0      3 suites  ±0   5m 52s ⏱️ +5s
2 015 tests ±0  2 015 ✅ ±0  0 💤 ±0  0 ❌ ±0 
2 016 runs  ±0  2 016 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 78b312f. ± Comparison against base commit 92006e8.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

752 tests  ±0   560 ✅ ±0   7m 8s ⏱️ -8s
  3 suites ±0   192 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit 78b312f. ± Comparison against base commit 92006e8.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    5 files  ±0      5 suites  ±0   15m 45s ⏱️ +8s
4 163 tests ±0  4 161 ✅ ±0  2 💤 ±0  0 ❌ ±0 
4 167 runs  ±0  4 165 ✅ ±0  2 💤 ±0  0 ❌ ±0 

Results for commit 78b312f. ± Comparison against base commit 92006e8.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

   17 files  ±0     17 suites  ±0   35m 55s ⏱️ +22s
9 404 tests ±0  9 210 ✅ ±0  194 💤 ±0  0 ❌ ±0 
9 413 runs  ±0  9 219 ✅ ±0  194 💤 ±0  0 ❌ ±0 

Results for commit 78b312f. ± Comparison against base commit 92006e8.

@meshweaver-cloud
meshweaver-cloud Bot added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit ef69e3c Sep 25, 2026
44 checks passed
@rbuergi
rbuergi deleted the fix/295-vault-structure-refuse branch October 10, 2026 13:10
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.

2 participants