_env_bool returned the default for anything outside {true,1,yes}, so
BAMBUDDY_OIDC_REQUIRE_EMAIL_VERIFIED=on silently read as OFF and
BAMBUDDY_OIDC_ENABLED=on silently disabled the provider -- the exact
opposite of what .env.example claimed. Unrecognized values now raise
EnvOIDCConfigError, caught in _apply_env_oidc_provider the same way a
bad DEFAULT_GROUP or a ValidationError already is: logged and left
running, never released on a typo.
Also promotes _env_bool to env_bool now that it has a call site in
auth.py, and corrects the boolean-parsing sentence in .env.example.
.env.example described what the required vars do but not two sharp
edges: the issuer must be a public HTTPS URL (an in-cluster
http://keycloak:8080 is silently refused), and BAMBUDDY_OIDC_NAME
matches an existing UI-created provider by name and takes it over.
Without it every account auto-created through the env provider fell back to
Viewers (routes/mfa.py), and because the provider is locked the UI could not
correct it either -- a real limitation for a declarative deployment running
BAMBUDDY_OIDC_AUTO_CREATE_USERS=true.
BAMBUDDY_OIDC_DEFAULT_GROUP names a group rather than an id: ids are handed out
per installation, so the same compose file would point at a different group on
the next deployment. The name is matched exactly, resolved against the database
before anything is written, and default_group_id joins _APPLIED_FIELDS so
dropping the variable clears the group again -- the environment is the whole
truth for this row.
A name that matches no group is refused rather than defaulted: silently landing
users in Viewers is the failure this variable exists to remove, and the API
already answers 422 for a default_group_id that does not exist. The refusal is
logged and survivable, and it says which of the two cases happened, because
they differ sharply -- an existing provider keeps running on its last good
config, while on a first boot nothing is created and no SSO button appears.
Raised by maziggy in review of #2625 as a scope decision; documented in
.env.example and in the companion wiki PR.
Follows the BAMBUDDY_LOCAL_LOGIN block's style: what it is for, when it
activates, and the two things an operator cannot guess from the variable names
-- that removing the config disables rather than deletes the provider, because
deleting would permanently drop every account link, and that the UI shows it
read-only because startup would overwrite an edit anyway.
Also states why auto-link is refused without verified emails, since that is
the one setting that will be silently skipped if someone gets it wrong.
Refs #2593
Adds a global local_login_enabled setting plus a per-provider
is_autologin flag on OIDCProvider so operators who run their own SSO
enabled, or if the calling admin has no UserOIDCLink — either would
lock everyone out. App-layer invariant: at most one provider can carry
is_autologin; setting it on one clears it on every other.
/auth/advanced-auth/status surfaces both new fields so the LoginPage
decides UI in one query. The env-var bypass flips the reported
local_login_enabled back to true so the SPA matches what the route
will accept.
chore(i18n): extend parity gate to all locales with strict/info tiers
Previously the script only inspected en/zh-CN/zh-TW, leaving de/fr/it/ja/pt-BR
drift invisible. Now locales are auto-discovered from src/i18n/locales/, and a
STRICT list (de, zh-CN, zh-TW — currently in parity) gates CI while the rest
report informationally until their drift is caught up. ja notably has 27 real
placeholder bugs worth fixing before promotion to strict.
Bambuddy ships strict anti-clickjacking headers (X-Frame-Options:
SAMEORIGIN + CSP frame-ancestors 'none') by default. Internet-exposed
deployments need this; same-LAN HA Webpage-panel users do not, and
SAMEORIGIN is port-strict so HA on :8123 + Bambuddy on :8000 always
fails. azurusnova hit exactly that case.
Add TRUSTED_FRAME_ORIGINS env var (comma-separated scheme://host[:port]).
When set, drop X-Frame-Options entirely (modern browsers honor
frame-ancestors and the legacy ALLOW-FROM syntax is deprecated /
inconsistent across vendors) and emit "frame-ancestors 'self' <list>"
on every CSP-bearing route. Origin validation is strict: only http(s),
no paths, no query/fragment, no wildcards. Bad entries get a warning
and are dropped — startup never fails.
Default behaviour (no env var) is unchanged: X-Frame-Options:
SAMEORIGIN + frame-ancestors 'none', so existing Docker / bare-metal
deployments are not affected.
- Add HA_URL and HA_TOKEN environment variables for automatic HA
integration configuration in HA add-on deployments
- Environment variables always override database settings with
non-negotiable precedence; database values preserved for fallback
- Auto-enable integration when both env vars are set; partial config
(one env var) uses database enable state without auto-enabling
- Add centralized get_homeassistant_settings() function following
Spoolman pattern; replace direct database queries across codebase
- Add ha_url_from_env, ha_token_from_env, ha_env_managed fields to
AppSettings schema to inform frontend about configuration source
- UI shows read-only fields with lock icons and "(Environment Managed)"
labels when env-controlled; toggle shows auto-enable badge
- Add comprehensive test coverage: 9 integration + 8 unit tests
Closes#283