feat(bridge-auth): send X-Admin-Token on all /xiaozhi/admin/* calls#152
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR completes the bridge-side wiring for the admin-auth epic by conditionally attaching an X-Admin-Token header (sourced from DOTTY_ADMIN_TOKEN) to bridge→xiaozhi /xiaozhi/admin/* requests, staying a no-op until the coordinated enforcement flip.
Changes:
- Add
_xiaozhi_admin_headers()helpers (backed by module-level_ADMIN_TOKEN) inbridge.pyandbridge/dashboard.py. - Thread the helper through all updated bridge/dashboard
/xiaozhi/admin/*HTTP call sites (requests + urllib). - Add unit tests covering header helper behavior and one integration path through
_dispatch_abort.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
bridge.py |
Adds admin-token helper and applies it to bridge-side admin POST dispatchers. |
bridge/dashboard.py |
Adds admin-token helper and applies it to dashboard admin GET/POST calls (urllib + requests). |
tests/test_admin_headers.py |
Adds tests validating helper behavior and header propagation via _dispatch_abort. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+169
to
+176
| _ADMIN_TOKEN = os.environ.get("DOTTY_ADMIN_TOKEN", "").strip() | ||
|
|
||
|
|
||
| def _xiaozhi_admin_headers() -> dict: | ||
| """X-Admin-Token header for /xiaozhi/admin/* requests when DOTTY_ADMIN_TOKEN | ||
| is set (matches the xiaozhi-server middleware); empty dict otherwise, so the | ||
| bridge is a no-op until the coordinated enforcement flip.""" | ||
| return {"X-Admin-Token": _ADMIN_TOKEN} if _ADMIN_TOKEN else {} |
| _ADMIN_TOKEN = os.environ.get("DOTTY_ADMIN_TOKEN", "").strip() | ||
|
|
||
|
|
||
| def _xiaozhi_admin_headers() -> dict: |
Admin-auth epic, part 4 of 4 (bridge caller — the scattered one). Pairs with the permissive /xiaozhi/admin/* middleware (part 1). Adds a `_xiaozhi_admin_headers()` helper (reads DOTTY_ADMIN_TOKEN into a module-level `_ADMIN_TOKEN`) to both bridge.py and bridge/dashboard.py, threaded through every admin call site: - bridge.py: _dispatch_abort / _dispatch_set_state / _dispatch_set_toggle and the dashboard _dashboard_abort_device / _dashboard_inject_to_device helpers (5 POSTs). - dashboard.py: _xiaozhi_device_count + _xiaozhi_list_songs (urllib GETs, now via urllib.request.Request with headers) and play_song's play-asset POST (3 sites). Calls to dotty-behaviour (vision photo proxy, perception getters) are deliberately NOT given the header. Header only sent when the token is set — no-op until the flip. Tests: new tests/test_admin_headers.py (6 cases) — both helpers set/unset, and an integration through _dispatch_abort capturing the headers kwarg. Full tests/ 71 passed; ruff clean. Completes the foundation: #149 (server) + #150 (behaviour) + #151 (pi-ext) + this. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e579b98 to
30706cc
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.
Admin-auth epic — part 4 of 4 (bridge caller, the scattered one). Pairs with the permissive
/xiaozhi/admin/*middleware (#149). Offmain. Completes the foundation.Adds a
_xiaozhi_admin_headers()helper (readsDOTTY_ADMIN_TOKENinto module-level_ADMIN_TOKEN) to bothbridge.pyandbridge/dashboard.py, threaded through every admin call site:_dispatch_abort/_dispatch_set_state/_dispatch_set_toggle, plus the_dashboard_abort_device/_dashboard_inject_to_devicehelpers._xiaozhi_device_count+_xiaozhi_list_songs(urllib GETs →urllib.request.Requestwith headers) andplay_song's play-asset POST.Calls to dotty-behaviour (vision photo proxy, perception getters) deliberately do not get the header. Header only sent when the token is set — no-op until the enforcement flip.
Tests: new
tests/test_admin_headers.py(6 cases) — both helpers set/unset + an integration through_dispatch_abortcapturing the headers kwarg. Fulltests/71 passed; ruff clean.Epic status
Foundation complete across all 4 services: #149 (server middleware) · #150 (behaviour) · #151 (pi-ext) · this (bridge).
Next — the enforcement flip (separate ops step, when you're ready): set the same
DOTTY_ADMIN_TOKENin all 4 container envs, deploy callers first (bridge/behaviour/pi-ext), xiaozhi last. Until then everything is a no-op.🤖 Generated with Claude Code