feat(rotation): Phase 3 — manual rotate UI + handlers (#72) - #130
Merged
sarg3nt merged 1 commit intoMay 17, 2026
Merged
Conversation
4 tasks
Surfaces the Phase 2 rotator behind two operator-visible buttons —
the bit that makes the keyring work actually usable. No new
back-end abstractions; just two thin handlers that compose the
existing rotator with the dashboard's box management.
Backend
-------
`POST /settings/boxes/{id}/rotate-key`
- Rotates one box. Returns 200 with `{success, new_kid, old_kid,
retire_after}` or 4xx/5xx with `{success: false, message}`.
- Constructs a rotator per request from the handler's existing DB +
encryptor — no new singletons.
`POST /settings/boxes/rotate-key-all`
- Iterates every enabled box and rotates each through the same
rotator. Reports per-box success/failure so the operator sees
exactly which boxes need follow-up. Failures on one box don't
halt the run; this matches the homelab use case better than a
strict circuit-breaker — operator decides whether to investigate
one bad box or move on.
Both routes are wired into the admin-only `/settings` group in
cmd/server/main.go alongside the existing box CRUD routes; same
permission gate as `HAProxyBoxUpdatePost` etc.
UI
--
Box edit form (`HAProxyBoxEditPage`)
- New "Rotate API key" section under the API-Key field with a Rotate
Key button. Visible only on edit (server != nil).
- Click → `showConfirmDialog` (warning style) explaining the 24h
overlap → POST → toast on success or alert dialog on failure.
- Reuses the in-page rotate-spinner SVG to surface in-flight state.
Boxes list (`HAProxyBoxesPageContent`)
- New "Rotate All Keys" button next to the existing "Add Box"
button. Visible only when at least one box exists.
- Click → confirm → POST → success toast or alert dialog with a
per-box failure list when partial.
JS uses the established `showConfirmDialog` / `showAlertDialog` /
`showToast` APIs from `layouts.Base`, per the CLAUDE.md "never use
native confirm/alert/prompt" rule.
Tests
-----
No new tests — the rotator's behaviour is already covered by
`services/agent_keyring/rotator_test.go` (Phase 2). The handlers
are thin enough that adding HTTP-level tests would duplicate the
rotator-side coverage. Browser-level testing of the new UI was not
performed in this commit; operator should smoke-test by hitting
both buttons end-to-end before merging.
Refs: Phase 3 of the implementation plan posted to #72.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
sarg3nt
force-pushed
the
feature/issue-72-phase-2-rotation-endpoints
branch
from
May 17, 2026 19:03
b606c7c to
d174a75
Compare
sarg3nt
force-pushed
the
feature/issue-72-phase-3-rotate-ui
branch
from
May 17, 2026 19:03
c66f37a to
139e7b7
Compare
sarg3nt
merged commit May 17, 2026
dc36728
into
feature/issue-72-phase-2-rotation-endpoints
3 checks passed
4 tasks
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
Stacked on #129 (Phase 2). Surfaces the rotator behind two operator-visible buttons — the bit that makes the keyring work actually usable.
Backend
POST /settings/boxes/{id}/rotate-key— rotates one box. Returns{success, new_kid, old_kid, retire_after}or 4xx/5xx with{success: false, message}. Constructs a rotator per request from the handler's existing DB + encryptorPOST /settings/boxes/rotate-key-all— iterates every enabled box. Reports per-box success/failure so the operator sees exactly which boxes need follow-up. Failures don't halt the run; operator decides whether to investigate or move onBoth routes wired into the admin-only
/settingsgroup alongside existing box CRUD. Same permission gate asHAProxyBoxUpdatePost.UI
showConfirmDialog(warning style explaining the 24h overlap) → POST → toast on success or alert dialog on failureshowConfirmDialog/showAlertDialog/showToastAPIs per the CLAUDE.md "never use native confirm/alert/prompt" ruleTest plan
GET /api/v1/system/keyring)Stack
Phase 3 of 5. Base:
feature/issue-72-phase-2-rotation-endpoints(#129).Closes part of #72.
🤖 Generated with Claude Code