mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-19 15:54:27 +02:00
feat(system): NTP-gate state on /api/v1/system/appliance
Extends the appliance endpoint that landed in the previous commit with a
time_synced field, sourced from /run/bambuddy/time-synced (the appliance's
ntp-gate.sh writes this once chronyd reports sync, or with a "warning"
marker after the 3-minute timeout). The RPi 5 has no battery-backed RTC,
so on a fresh boot the system clock is wrong until NTP catches up -- JWT
expiries and TLS certificate validity windows depend on this being right.
Exposing the gate lets the SPA render a "time not synced" indicator while
that's still true and clear it once "ok" comes through.
backend/app/core/local_config.py
New read_ntp_gate(path) function alongside read_local_toml. Three states:
"ok" chrony reported sync within the 3-minute window
"warning" 3-minute timeout elapsed without sync; user already waited
and the wizard proceeded with a degraded clock
None file absent (non-appliance install), OSError, empty content,
unknown marker, or binary garbage -- "unknown / don't gate"
Defensive read mode (errors="replace") survives non-utf8 content without
crashing. Module docstring broadened from "local.toml reader" to "small
readers for appliance-set state files".
backend/app/api/routes/system.py
/system/appliance now returns:
{hostname, timezone, locale, time_synced}
with the same no-auth posture: bootstrap surfaces (i18n init, time-sync
banner) read this before auth might be set up, and the contents are
non-secret (user-set defaults + a public sync flag). The endpoint
docstring expands to explain the RTC motivation -- otherwise the
time_synced field reads like a leftover.
This commit is contained in:
@@ -16,7 +16,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from backend.app.core.auth import RequirePermissionIfAuthEnabled
|
||||
from backend.app.core.config import APP_VERSION, settings
|
||||
from backend.app.core.database import get_db
|
||||
from backend.app.core.local_config import read_local_toml
|
||||
from backend.app.core.local_config import read_local_toml, read_ntp_gate
|
||||
from backend.app.core.permissions import Permission
|
||||
from backend.app.models.archive import PrintArchive
|
||||
from backend.app.models.filament import Filament
|
||||
@@ -608,16 +608,26 @@ async def get_system_health(
|
||||
|
||||
@router.get("/appliance")
|
||||
async def get_appliance_defaults():
|
||||
"""Expose the hostname/timezone/locale the appliance setup wizard collected.
|
||||
"""Expose appliance-set state for the SPA's bootstrap surface.
|
||||
|
||||
Read from /etc/bambuddy/local.toml; absent on non-appliance installs, in
|
||||
which case all fields are null. No auth required — the frontend i18n
|
||||
bootstrap reads this BEFORE auth might be set up, and the contents are
|
||||
purely user-set defaults (no secrets).
|
||||
Two file sources, both optional and silently degraded when absent:
|
||||
|
||||
- ``/etc/bambuddy/local.toml`` — hostname / timezone / locale the
|
||||
firstboot wizard collected.
|
||||
- ``/run/bambuddy/time-synced`` — chrony NTP gate state. The RPi 5 has
|
||||
no battery-backed RTC, so on a fresh boot the clock is wrong until
|
||||
ntp-gate.sh writes "ok" (or "warning" if 3-minute timeout elapsed).
|
||||
A warning state means JWT expiries and TLS validity windows may be
|
||||
misaligned; the UI should surface this.
|
||||
|
||||
No auth required — the frontend bootstrap reads this BEFORE auth might
|
||||
be set up, and the contents are user-set defaults plus a public sync
|
||||
flag (no secrets).
|
||||
"""
|
||||
config = read_local_toml()
|
||||
return {
|
||||
"hostname": config.get("hostname"),
|
||||
"timezone": config.get("timezone"),
|
||||
"locale": config.get("locale"),
|
||||
"time_synced": read_ntp_gate(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user