Skip to content

feat: hub identity and config endpoints (CO1 2.3, 2.4)#50

Merged
NeonDaniel merged 7 commits into
NeonGeckoCom:devfrom
OscillateLabsLLC:feat_co1_hub_endpoints
Apr 16, 2026
Merged

feat: hub identity and config endpoints (CO1 2.3, 2.4)#50
NeonDaniel merged 7 commits into
NeonGeckoCom:devfrom
OscillateLabsLLC:feat_co1_hub_endpoints

Conversation

@mikejgray
Copy link
Copy Markdown
Contributor

Summary

  • Hub Identity (CO1 2.3): GET /hub/identity returns a stable, memorable hub ID (e.g. bold-crystal-synapse), user-configurable display name, and software version. POST /hub/identity (auth required) updates the display name. Hub ID is generated once at first boot and persisted to config.
  • Hub Config (CO1 2.4): GET /hub/config returns the active TTS, STT, and LLM engine names. TTS/STT are read from neon.yaml with known defaults (neon-tts-plugin-coqui, neon-stt-plugin-nemo) as fallback. LLM is hardcoded to "Neon Classic". Gracefully handles missing, malformed, or unreadable neon.yaml for non-Hub deployments.
  • Both discovery endpoints are public (no auth) so Nodes can identify and inspect a Hub during network discovery.

Files changed

  • neon_hana/hub_id.py — Docker-style 3-word kebab-case ID generator (new)
  • neon_hana/schema/hub_requests.py — Pydantic v2 request/response models (new)
  • neon_hana/app/routers/hub.py — Hub router with identity + config endpoints (new)
  • neon_hana/app/__init__.py — Register hub router
  • tests/test_hub_id.py — Generator unit tests (new)
  • tests/test_app.py — 16 new endpoint and edge case tests

Test plan

  • GET /hub/identity returns 200 with non-empty hub_id, display_name, version
  • hub_id is stable across requests and container restarts
  • POST /hub/identity with valid auth updates display name (whitespace stripped)
  • POST /hub/identity without auth returns 401/403
  • GET /hub/config returns TTS/STT module names from neon.yaml
  • GET /hub/config returns defaults when neon.yaml has no TTS/STT keys
  • GET /hub/config returns null TTS/STT when neon.yaml is absent
  • All 45 tests pass in Docker (ghcr.io/neongeckocom/neon-hana:dev)

GET /hub/identity returns a stable hub ID, user-configurable
display name, and HANA version. The hub ID is a memorable
three-word kebab-case identifier (e.g. "bold-crystal-synapse")
generated eagerly at startup and persisted to config.

POST /hub/identity (auth required) allows updating the display
name, which is stripped of whitespace and validated for length.

The GET endpoint is intentionally public (no auth) so Nodes can
identify a Hub during network discovery.
Reads neon.yaml to expose active TTS and STT plugin names, with
known defaults as fallback. LLM hardcoded to "Neon Classic" until
BrainForge has a config surface. Gracefully handles missing,
malformed, or unreadable neon.yaml for non-Hub deployments.
@mikejgray
Copy link
Copy Markdown
Contributor Author

Note on CI failure: The test failure is pre-existing and unrelated to this PR. test_mq_websocket_api.py fails during collection because ovos_utils.signal was removed upstream in a newer ovos-utils release:

neon_utils/file_utils.py:37: in <module>
    from ovos_utils.signal import ensure_directory_exists
E   ModuleNotFoundError: No module named 'ovos_utils.signal'

The import chain is test_mq_websocket_api.pyMQWebsocketAPIneon_iris.clientneon_utils.file_utilsovos_utils.signal. Last successful dev CI run was February 26 — the dependency break happened sometime after that.

All 45 tests in this PR pass locally in Docker (ghcr.io/neongeckocom/neon-hana:dev).

Copy link
Copy Markdown
Member

@NeonDaniel NeonDaniel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple minor suggestions. I still need to deploy and test this before approving

Comment thread neon_hana/app/routers/hub.py
Comment thread neon_hana/schema/hub_requests.py Outdated
- Replace local LLMConfig with LLMPersona from neon-data-models so the
  /hub/config response shape matches the rest of the LLM API surface
- Add TODO comment in /hub/config noting that the neon.yaml fallback
  assumes shared local FS with core services; future work should add
  messagebus handlers (opm.tts.query/opm.stt.query) as an alternative
  for split deployments
@NeonDaniel
Copy link
Copy Markdown
Member

NeonDaniel commented Apr 15, 2026

RE test failures and container errors, adding neon-utils>=1.14.1a1 to requirements.txt should resolve the import error.

Copy link
Copy Markdown
Member

@NeonDaniel NeonDaniel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deployed and tested at hana.neonaialpha.com. Noted a permissions check to implement and some exceptions I ran into that might be handled gracefully

Comment thread neon_hana/app/routers/hub.py Outdated
Comment thread neon_hana/app/routers/hub.py Outdated
- POST /hub/identity now requires hub: ADMIN permission via RBAC
  check using PermissionsConfig.from_roles(), matching the pattern
  used in get_user and node_server endpoints
- Gracefully handle read-only filesystem (k8s deployments) when
  persisting hub_id at startup and display_name on update. Startup
  logs an error and continues; update returns a warning field so the
  caller knows the change won't survive a restart
- Add HubIdentityResponse.warning field (null when everything is fine)
- New test: test_hub_identity_update_insufficient_permissions verifies
  guest users get 403 on the update endpoint
Fixes the pre-existing CI failure where test_mq_websocket_api.py
fails to collect due to ModuleNotFoundError on ovos_utils.signal.
The newer neon-utils pins a compatible ovos-utils version.
When node_auth=true, issued tokens get AccessRoles.NODE for all
permission fields regardless of the user's actual permissions. This
allows Node devices to authenticate as a real user but with limited
privileges — they can connect to the websocket and read hub config,
but cannot manage users or access admin endpoints.

Designed for QR code pairing: the Node scans credentials for a real
user account and calls /auth/login with node_auth=true to get
appropriately scoped tokens.
Comment thread neon_hana/auth/client_manager.py
@NeonDaniel NeonDaniel merged commit e28f293 into NeonGeckoCom:dev Apr 16, 2026
6 checks passed
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