feat: commit-confirmed apply (optional apply-confirm integration)#11
Merged
Conversation
111a7aa to
ad1a0f0
Compare
ad1a0f0 to
d6471a0
Compare
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
Adds safe-apply / commit-confirmed rollback to uapi. A config write can arm a deadline via
X-Uapi-Confirm: <seconds>(or?confirm=fallback): uapi snapshots the affected uci packages, commits, and returns 202 + a token; unless the client acks viaPOST /confirm/<token>before the deadline, the pre-change snapshot is restored automatically — surviving reboot, process kill, and a dead management path. This protects against the case ordinary atomic writes can't: a change that reloads cleanly yet severs the only path to the box.The rollback timer and durable state live in a separate package,
apply-confirm(uapi invokes its CLI, runs no daemon of its own — preserving the zero-bloat / no-aux-process principle). The integration is optional and feature-detected: absent the binary, a confirmed write returns501 confirm_unavailableand ordinary writes are byte-identical to before.Design decisions (from the planning session): client-driven ack (uapi never auto-acks — auto-acking on local reload success would defeat the lockout case); optional dependency (no hard
DEPENDS); uapi passes its ownresource.reloadset tostage --serviceso a rollback reloads exactly what the apply did;confirmvocabulary.Wire surface (additive)
X-Uapi-Confirm: <1..3600>header (or?confirm=) on any config write (resource POST/PUT/PATCH/DELETE, singleton PATCH,/batch). Arming needs no extra scope.202 Accepted+confirmbody block +X-Confirm-Token/X-Confirm-Deadlineheaders.GET /confirm,GET|POST|DELETE /confirm/<token>→ list / status / ack / rollback.uapi:confirm(:rofor status+list,:rwfor ack+rollback).confirm_unavailable(501),already_armed(409),confirm_window_closed(409),confirm_stage_failed(503),rollback_reload_failed(500).Implementation
src/lib/apply_confirm.uc(new): CLI wrapper; every interpolated value (package/service names, timeout, token) validated against an anchored regex before it reachesfs.popen(the injection control).src/lib/transaction.uc: stage between validate-success and commit (apply-confirm snapshots the pre-change on-disk config); revert on stage failure; disarm the window if commit/reload throws after arming (so a stale rollback can't fire);_attach_confirmcarries the token on success and disarms on in-band revert.src/lib/handler.uc:translate_txemits 202 + token; confirmed DELETE routes throughtranslate_tx(not the bare-204 short-circuit) so the token isn't dropped.src/main.uc: parsectx.confirm;/confirmrouting; thread confirm into/batch.build/gen_openapi.uc: header param,ConfirmWindowschema,PendingConfirm202 response on config writes,/confirm/*paths (all markedx-uapi-requires: apply-confirm).Sequencing
The wire surface lands now, but the 2.3.0 tag is held until apply-confirm reaches a stable, feed-published release (it soaks RC-first as a safety primitive). No
DEPENDS; installation.md documentsapk add apply-confirmas the opt-in.Tests / verification
make lint+make test(775 pass, +19) +make coverage(81.9% direct, 100% module) +make openapi-checkall green.translate_tx202 shaping (incl. null-body delete).45_apply_confirm_test.sh): graceful-degrade smoke (runs in current CI, apply-confirm absent) + full stage→ack and stage→timeout-rollback happy path (runs once apply-confirm is installable; same install-guard pattern as40_unbound).Companion
apply-confirm's
docs/cli-contract.mdis corrected separately (the "uapi 3.x" reference → 2.3.0, and the stale "uapi acks after its own reload" line → client-driven ack).