✨ Add profile option to switch NetBird profiles - #426
Conversation
Closes #423. A NetBird profile is simply its own config file: each one holds a separate peer identity, management URL and credentials. The add-on hardcoded a single config path, so it could only ever join one network. Add a `profile` option that selects `/config/profiles/<name>.json`. Leaving it empty keeps the existing `/config/config.json`, so current installs are unaffected. Home Assistant can switch networks by changing the option and restarting the add-on; DOCS.md shows the rest_command/script to do that. The upstream `netbird profile` commands are not an option here: they dial the daemon over gRPC, which `netbird up --foreground-mode` never starts. The schema wraps the name grammar in an optional group so the stored empty default still validates (same shape as `hostname` after #411), and the run script re-validates the name before it becomes a file path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughThe add-on adds a validated ChangesProfile selection
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds a Home Assistant add-on option to select a NetBird “profile” by switching which config JSON file netbird up uses, enabling HA automations to swap identities/networks via an option change + add-on restart.
Changes:
- Add
profileoption to the add-on schema and UI translation. - Update the s6 run script to resolve
--configto either the default config or a per-profile config under/config/profiles/<name>.json. - Document profile usage and provide an example HA
rest_command+ script workflow for switching profiles safely.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
netbird/config.yaml |
Adds profile option + schema validation for profile names. |
netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run |
Selects the config path based on profile and passes it via --config. |
netbird/DOCS.md |
Documents the new option and shows how to switch profiles from HA automations. |
netbird/translations/en.yaml |
Adds UI strings for the new profile option. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
bashio prints "null" both for an option that is not set and for the literal string, and cannot tell them apart — even bashio::config.exists conflates the two. A profile named "null" would therefore have silently fallen back to the default config and joined the wrong network with no error. The script cannot resolve this, so exclude the name at the schema level, which is the layer that can. Only the exact lowercase string is excluded: "nullx", "null_1" and "NULL" stay valid, matching the script's case-sensitive compare. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run (1)
45-47: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winUse the supported NetBird config path for this image.
netbirdio/netbird:0.74.6supportsnetbird up --config, but that flag is deprecated and emits a CLI warning. UseNB_CONFIG="${CONFIG_PATH}"for thisnetbird upinvocation or configurenetbird service run/reconfigurewith the chosen profile path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run` around lines 45 - 47, Update the netbird up invocation in the run script to use the supported NB_CONFIG environment variable set to CONFIG_PATH, avoiding the deprecated --config flag and its warning while preserving the selected profile configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@netbird/config.yaml`:
- Line 39: Update netbird/config.yaml at lines 39-39 to reject the literal
profile value null, preserving only the intended unnamed/default representation.
Update netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run at lines 34-40 so only
that unnamed representation selects CONFIG_DEFAULT_PATH; allow the literal null
to resolve to /config/profiles/null.json.
In `@netbird/DOCS.md`:
- Around line 82-87: Update the profile-name documentation near the
allowed-character description to state that names may be at most 64 characters
long, matching the schema and runtime validation.
- Around line 85-87: Update the configuration-path documentation in DOCS.md and
any matching external NetBird documentation to use Home Assistant’s mapped
paths: `/addon_configs/netbird-netbird` on the host and `/config` inside the
add-on. Replace references to `/addon_config/*_netbird`, including the profile
directory, while preserving the existing profile-name and filename guidance.
- Around line 130-143: Update the Supervisor REST command definitions
netbird_set_options and netbird_restart (and the preceding related command) so
their authorization headers send the required Bearer-formatted token rather than
the raw SUPERVISOR_TOKEN value. Ensure the configured environment variable or
supported request mechanism produces “Authorization: Bearer <SUPERVISOR_TOKEN>”
for every command.
- Around line 153-157: Update the documented netbird_set_options usage in both
referenced sections so the REST payload does not include setup_key, using a
secret-safe update path; alternatively, explicitly document the Home Assistant
debug/secure-log risk before users share or enable this script.
- Around line 153-158: Update the automation sequence around netbird_info and
netbird_set_options to capture the options update response in a response
variable, then validate both the information lookup and options update succeeded
before invoking netbird_restart. Keep the restart skipped whenever either call
fails, preventing activation of an unchanged profile.
In `@netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run`:
- Line 17: Update the legacy migration command in the run script so it moves
CONFIG_OLD_PATH to CONFIG_DEFAULT_PATH only when the destination does not
already exist, preserving the current profile. Handle and report migration
failures explicitly instead of silently ignoring mv errors.
---
Nitpick comments:
In `@netbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/run`:
- Around line 45-47: Update the netbird up invocation in the run script to use
the supported NB_CONFIG environment variable set to CONFIG_PATH, avoiding the
deprecated --config flag and its warning while preserving the selected profile
configuration.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a05014fb-134f-4d09-ac7d-d540822c2cb9
📒 Files selected for processing (4)
netbird/DOCS.mdnetbird/config.yamlnetbird/rootfs/etc/s6-overlay/s6-rc.d/netbird/runnetbird/translations/en.yaml
The pre-addon_config migration moved /homeassistant/netbird/config.json with an unconditional mv, so if both files existed it overwrote the current default config — discarding the live peer identity and credentials. Skip the move when the destination exists (warning, legacy file left in place for manual recovery) and fail loudly if the move itself fails, rather than starting up as an unregistered peer. Pre-existing behaviour, reported by CodeRabbit on #426 and fixed here because this change already touches that line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
From the #426 review: - Use the X-Supervisor-Token header instead of Authorization. A raw token in Authorization does work (Supervisor takes the last space-separated field), but this is the purpose-built header and removes the ambiguity. - Guard both calls on a 200 before restarting. A rest_command that receives an error response logs a warning and does not fail the script, so a rejected options update was still followed by a restart that came back on the old profile. - Warn that the posted payload carries setup_key. Home Assistant logs it at warning level when a call fails, and logs headers too (including the token) at debug level. - Document the 64-character limit and the reserved name null. - Describe the add-on config directory correctly: /config inside the add-on, exposed as /addon_configs/<slug> (plural, one directory per slug). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
I tested this on Home Assistant, and I think the current profile UX is a little confusing and makes it too easy to configure the wrong profile accidentally. When I change profile, the other fields (admin_url, management_url, setup_key, and hostname) keep the values from the previously selected profile. Those values are then passed to NetBird when the add-on starts with the new profile. There is no indication whether the selected profile already exists, and the form cannot show the settings stored in that profile’s JSON file. For example, I can configure a work profile, change the name to personal, and accidentally create or update personal using the URLs, setup key, and hostname left over from work. The description makes those fields sound profile-specific, but Home Assistant actually stores them as one global set of add-on options. Would it be safer to treat these fields as enrollment settings only? If the selected profile already exists, the add-on could ignore them and use the values in that profile’s configuration file. If the profile does not exist, it could require a specific create option before applying them. That would make switching profiles safe even though Home Assistant’s standard add-on form cannot dynamically load or clear fields when the profile name changes. |
|
@lfarkas any update here? |
Closes #423.
What
Adds a
profileadd-on option. A NetBird profile is simply its own config file — each one holds a separate peer identity, management URL and credentials — so pointing the client at a different config file switches the whole account/network it joins./config/config.json, exactly today's behaviourwork→/config/profiles/work.jsonHome Assistant switches networks by changing the option and restarting the add-on.
DOCS.mdgains a Switching profiles from Home Assistant section with therest_commands and script to do that from an automation.Why not
netbird profile ...The upstream profile commands (and
netbird up --profile) all dial the daemon over gRPC —client/cmd/up.gocallsswitchOrCreateProfilebefore branching into foreground mode. This add-on runsnetbird up --foreground-mode, which never starts that socket, so the native commands are unusable without reworking the add-on into daemon mode. Selecting the config file achieves the same result with 25 lines of shell.Notes for review
match(^([a-zA-Z0-9_-]{1,64})?$)?— the grammar is wrapped in an optional group so the stored""default still validates. This is the same shapehostnameuses after fix: accept empty values for optional url/hostname options #411; a barematch(^[a-zA-Z0-9_-]+$)?would re-break start-at-boot on every install storing the default.env_varsloop already does./homeassistant/netbird/config.json→/config/config.jsonmove still targets the default path and runs before profile selection, so an upgrading user's old credentials cannot land in a profile file./infoand merges before posting. A partial payload would silently resetsetup_keyand friends to their defaults.config.yamlversion:tracks the NetBird release and must match the Dockerfile tag, so this rides the next Renovate bump.Verification
shellcheckandbash -nclean; both YAMLs parse; every schema key has a translation.Two test harnesses were run locally (not committed — this repo has no test suite):
--configvalue. 10/10 pass: unset → default config,null→ default config, named profile → profiles dir, and../evil,a/b,/etc/shadow,a b, 65 chars all abort without invoking netbird. Includes a case asserting the legacy migration still lands in the default config when a profile is set.RE_SCHEMA_ELEMENTlifted verbatim from Supervisor'sapps/options.pyplusvol.Matchsemantics. 11/11 pass, confirming""is accepted and../evil,a/b,a.json, non-ASCII are rejected.Not verified locally:
yamllintand the add-on linter (no container registry access from my environment) — CI is the first real check. No live HAOS test, since that needs a built test image.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation