Skip to content

feat(set): schema-aware vaultctl set with extend prompt (#40 phase 3, closes #40)#52

Merged
f3rdy merged 3 commits intomasterfrom
feature/40-schema-aware-set
Apr 28, 2026
Merged

feat(set): schema-aware vaultctl set with extend prompt (#40 phase 3, closes #40)#52
f3rdy merged 3 commits intomasterfrom
feature/40-schema-aware-set

Conversation

@f3rdy
Copy link
Copy Markdown
Contributor

@f3rdy f3rdy commented Apr 28, 2026

Summary

Closes #40 — phase 3 of the schema lifecycle. `vaultctl set` now consults the project's CUE baseline before encrypting and reacts to structural changes that the schema doesn't cover.

The static foundation from phases 1+2 (`schema infer` + `schema sync`) lets users bootstrap and sync the schema explicitly. This phase makes the schema part of normal day-to-day flow: when a `set` would introduce a new key (or change a key's structure), the user sees the diff, and decides whether to accept it as a schema change or as drift.

UX

```
$ vaultctl set new_token "abc123"
Schema does not cover this change:
--- /home/.../vault.cue (current)
+++ /home/.../vault.cue (inferred)
@@ -3,4 +3,5 @@
#VaultFile: {
existing_key: string

  •   new_token: string
    

}

Extend .vaultctl/vault.cue with this change? [y/N]:
```

If "y": the baseline is rewritten to cover the new structure, then the vault is encrypted as usual.
If "n": a follow-up prompt asks "Proceed without updating schema?" — "y" continues with drift, "n" aborts and leaves the vault unchanged.

Non-Interactive Flags

Flag Behavior
`--extend-schema` Write the new baseline silently, continue.
`--no-extend-schema` Skip both prompts, accept drift; `vaultctl validate` flags it later.
`--force` (no flag) Implicitly `--no-extend-schema` — safer default for scripts.

The schema diff is still printed to stderr in non-interactive runs, so CI logs show what changed.

Implementation

  • `_apply_schema_aware_check()` in `cli.py` — pure orchestration: short-circuits when there's no baseline or no cue binary; otherwise validates, formats the diff, decides interactive vs flag-driven path.
  • The validation step strips `_previous` backup keys before comparing against the schema. This is the key correctness detail — without it, every `set` on an existing key would incorrectly report "schema does not cover" because the schema deliberately excludes `_previous` (those are an implementation detail of `set --backup`, not a real key shape).

Test Coverage

7 new CLI tests:

  • No baseline → schema check skipped silently.
  • Existing key, value change → no schema noise.
  • `--extend-schema` → baseline written, follow-up `schema sync` reports clean.
  • `--no-extend-schema` → baseline untouched, follow-up `schema sync` reports drift.
  • `--force` without flag → same as `--no-extend-schema`, but the diff still printed.
  • Interactive accept (`y`) → baseline updated.
  • Interactive decline + decline-proceed → abort, vault unchanged.

Total tests: 373 → 380. Coverage stable at 88%.

What's NOT in This PR

The big-picture design from #40 is now complete:

Possible future polish, not part of this PR:

Closes #40.
Refs #34.

f3rdy added 3 commits April 28, 2026 09:20
Phase 3 closes the #40 lifecycle loop. After computing the new vault
data but before encrypting, `set` validates against
`.vaultctl/vault.cue` (if baseline + cue both available). When the new
structure isn't covered:

- shows the schema diff for the change being made
- prompts to extend the baseline (default: no), then prompts to
  proceed with drift (default: no — abort, leave vault unchanged)

Non-interactive flags:
- --extend-schema: write the new baseline silently and continue
- --no-extend-schema: skip both prompts, accept drift (validate flags later)
- --force without flag: same as --no-extend-schema (safer default for scripts)

Detail: `_previous` backup keys are stripped from the validation input,
because the schema deliberately excludes them. Without this, every set
on an existing-key would falsely report "schema does not cover" simply
because pre-existing backups aren't in the schema.

7 new CLI tests cover: no baseline (skipped), existing-key set (silent),
both schema flags, --force-without-flag default, interactive accept,
interactive decline-and-abort.

Closes #40.
@f3rdy f3rdy merged commit a16cf9b into master Apr 28, 2026
2 checks passed
@f3rdy f3rdy deleted the feature/40-schema-aware-set branch April 28, 2026 07:40
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.

Schema lifecycle: vaultctl schema infer/sync and interactive extend

1 participant