Commit Graph

170 Commits

Author SHA1 Message Date
mlsmaycon
564df34112 [management] Scope the omitted-key sentence to updates that trigger a check 2026-08-27 09:03:25 +00:00
mlsmaycon
e85e18e5b9 [management] Document the fourth trigger for the update credential check 2026-08-27 08:46:24 +00:00
mlsmaycon
8a716f1294 [management] Check a record when TLS verification is switched back on
The skip-TLS exemption added a hole of its own. Such a record is stored without
being checked at all, and the re-check on update watched only the upstream, the
key and the catalog entry — so turning verification back on left a provider
that had never been checked now running as if it had. That transition is the
first moment the record can be checked, and it now is.

An update that preserves the stored key trims it on the way through, so a
record saved before keys were normalised is repaired by the next edit rather
than carrying whitespace the proxy still sends. That makes the comparison see a
change, which is right: the key has never been tested in the form it is about
to be sent in.

The create description also claimed more of the upstream than the check reads.
Only the host is used — the listing goes to the catalog's own path over HTTPS —
so a configured scheme or path is neither used nor validated there.
2026-08-27 08:33:57 +00:00
mlsmaycon
5720c33be9 [management] Fix what a second review found in the credential check
Four defects and two pieces of wording, from cubic's pass over the branch.

A provider that asks the proxy to skip TLS verification was checked with a
client that verifies it, so a self-hosted endpoint behind a self-signed
certificate was refused for the one reason its operator had already declared
they accept. Those records now save unchecked, alongside the other cases this
cannot speak for. Sending the credential over a connection management declines
to verify was the other way out, and a worse one.

A key pasted with surrounding whitespace passed its check and then failed every
request: the vendor call trims before building the auth header, the synthesiser
substitutes the stored value verbatim. The key is now stored in the form it
will be sent, so what was checked is what runs.

The proxy-guard test resolved api.openai.com for real before reaching its own
transport, and on a runner with no egress that lookup failed as an
UnreachableError too — so it passed while never exercising the socket guard it
is named for.

A DNS timeout said only that the lookup failed. It now says so as a timeout,
without borrowing the wording of a connection that was never attempted.

The create description promised more than the check delivers: for Bedrock the
runtime host is resolved but never contacted, so a public host that does not
answer is still stored. It says that now, and names the TLS exemption above.
The invalid-upstream message no longer quotes the URL back, which was the one
path in this feature that echoed what the operator typed.

The live suite's single-vendor scope and its dependence on vendor availability
are now stated where the tests are, rather than left to be rediscovered.
2026-08-27 08:15:06 +00:00
Maycon Santos
b23969db59 Merge branch 'main' into agent-network/provider-credential-check 2026-08-26 17:26:13 +02:00
mlsmaycon
afffc948eb [management] Regenerate the API types after the discovery request change
The generated file carries the schema descriptions as doc comments, so editing
them leaves it behind and the release job's diff check fails. Comments only —
no field or type moved.
2026-08-26 14:34:18 +00:00
mlsmaycon
11faa925ee [management] Check a vendor change, and bound the check by one deadline
Two gaps a review surfaced.

Moving a record from one catalog provider to another changed neither field the
check looked at, so an unchanged credential started being offered to a
different vendor, under a different auth header, with nothing asking whether it
was accepted there.

And each host lookup built its own eight-second budget from a background
context, so a slow resolver could spend one before the request spent another,
and a caller that gave up was still waiting. Bedrock made that three: it now
checks its runtime host as well. One deadline is taken at the top of Fetch and
carried through both lookups and the request.

The create description also had the exemption backwards, reading as though an
upstream the check cannot reach is stored unverified. Unreachable blocks; only
what cannot be checked at all is exempt.
2026-08-26 14:23:58 +00:00
Viktor Liu
51095cb986 [client, management] Support per-peer lazy connection state and default proxy peers to lazy (#6762)
* Support per-peer lazy connection state and default proxy peers to lazy

* Classify forward targets from incoming config in lazy exclusion

* Set IsUserspaceBind mock so lazy manager starts in engine test

* Skip lazy exclude reconciliation when the set is unchanged

* Keep cached lazy flag when a sync carries no peer config
2026-08-26 09:33:51 +02:00
mlsmaycon
8dcdaeb799 [management] Let a discovery request name a record and a new upstream
Editing a provider's upstream URL meant retyping its API key. The key is the
one field the API never returns, so there was nothing to retype from, and the
dashboard had to demand it because a provider_id request resolved the upstream
from the stored row — listing the old endpoint while the form showed the new
one.

The request now reads as a partial edit of the record it names, the same way
PUT on a provider already does: an upstream in the body overrides the stored
one, an omitted upstream keeps it. The credential and the catalog entry still
come from the record only, so a caller cannot aim a stored key at a vendor of
their choosing.
2026-08-26 07:05:44 +00:00
Zoltan Papp
15fff4c164 [client] Sweep connections on network loss via a shared netevents manager (#7254)
Losing the last network only flipped the availability state: the dead management, signal and relay sockets stayed silently connected until their own timeouts, so the client kept reporting Connected with no network at all.

Introduce client/netevents with a Manager that ties the availability state, the connection sweeper and the status recorder together, and move the netstate and netsweep packages under it (netsweep renamed to sweep). SetNetworkAvailable(false) now also sweeps the registered connections so their owners redial and the listener reaches the NoNetwork state.

The Android and iOS bindings own a Manager instance and inject it through the constructors; consumers hold the concrete *Manager whose nil zero value reports always-online and never sweeps, with interfaces kept only as parameter contracts. The relay guard settle wait moved into the Manager as WaitSettled, removing the netevents import from the relay package.
2026-08-25 18:43:19 +02:00
mlsmaycon
8643faeed5 [management] Document the provider credential check, and prove it live
The OpenAPI change is the 422 both provider routes can now answer, plus what
decides it: the create path checks the pair before storing, the update path
checks only when the upstream or the key moved, and an update omitting the key
is checked against the stored one.

The live tests cover what a unit test structurally cannot. Mocked refusals
prove the classifier maps a status to a message; they cannot show that these
vendors refuse a bad key on their listing endpoint at all, which is the
assumption the feature rests on. The good-key case earns its place beside the
bad one — a check that refused everything would satisfy a test asserting only
the refusal.

The rotation case pins the state worth the most: after a rejected key, an edit
that reuses the stored one still passes. The API never returns a key, so that
is the only way to show the working credential is still there.
2026-08-24 06:08:16 +00:00
Maycon Santos
f03853867b [proxy,management] Serve Bedrock model discovery from the control plane (#7250)
[proxy,management] Serve Bedrock model discovery from the control plane

A Bedrock provider could never answer a model-discovery request. The router
sent GET /inference-profiles to the record's upstream, which has to be
bedrock-runtime.<region> for InvokeModel to work, and that host does not
implement the operation. ListInferenceProfiles is a control-plane operation on
bedrock.<region>.amazonaws.com, and one provider record carries one upstream,
so the two hosts genuinely differ.

The route now carries a discovery host, taken from the catalog's declaration
with the region read back out of the configured upstream, and the listing — and
only the listing — goes there. Inference is untouched. A proxied or self-hosted
Bedrock endpoint gets no discovery host at all rather than a guessed one, since
inventing a host would send the operator's credential somewhere they never
configured.

Two things had to follow for the listing to be usable once it arrives. The
response filter only understood OpenAI's {"data":[{"id":…}]}, so a Bedrock
listing fell through it untouched, offering every profile in the account
whatever the policy said. And discoverableModels intersected by exact string,
so a record registering the raw profile id while a guardrail names the catalog
key intersected to nothing — bounding a working provider's listing down to
empty.

Normalisation is the third. The geography in front of a cross-region profile
was matched against a hardcoded list of four, so every profile issued under jp,
au, ca, sa or us-gov carried its prefix into the pricing key, matched no
catalog entry and metered at zero. It is now recognised by either the geography
or the vendor that follows it, so an id has to be new on both axes at once to
slip through — a live eu-central-1 listing returned "global.xai.grok-4.6" days
after the vendor list was first written.
2026-08-23 20:29:10 +02:00
Maycon Santos
5e88d3f87a [management] Offer a provider's live model list in the config form (#7246)
[management] Offer a provider's live model list in the config form

Adds POST /api/agent-network/catalog/providers/models, which asks a vendor
which models an operator's own credential can actually reach, so the provider
form can offer a live list instead of only the compiled-in catalog. The catalog
goes stale, and it cannot see an account: which OpenAI models an org is
entitled to, which Bedrock inference profiles an account and region hold, which
Vertex models a project has enabled.

The endpoints, auth headers and response shapes come from probing the live APIs
(#7244); each vendor invented its own envelope and none can be guessed from the
request. Bedrock shaped the design: its listing lives on the control plane
while inference must go to the runtime host, so Discovery carries its own host
rather than reusing the record's upstream, and profile ids are taken verbatim
because the region prefix is what AWS requires at invoke time.

A caller supplies either the key they are typing or the id of a saved record
whose stored credential is reused — never both, since accepting both would run
an arbitrary credential under the identity of a record the caller may only be
permitted to read. Gated on Create rather than Read, because this spends the
operator's credential against a third party.

Management has not made outbound calls on an operator's behalf before and it
holds a credential for every provider, so every resolved address must be public
— covering loopback, RFC1918, the cloud metadata address and NetBird's own
100.64/10 range — and redirects are not followed, since a redirect moves the
request to a host the check never saw.

The vendor is authoritative for the id; the catalog stays authoritative for
pricing. A discovered model the shipped table cannot price returns
pricing_known: false so the operator must set rates rather than being
registered at a silent zero.
2026-08-23 20:21:25 +02:00
Maycon Santos
766fcae3f8 [proxy,management] Conform the Agent Network endpoint to the LLM gateway protocol (#7154)
[proxy,management] Conform the Agent Network endpoint to the LLM gateway protocol

Reviewed the proxy against Claude Code's published gateway contract. The
transport layer already held up; fourteen gaps sat one layer up, in the model
catalog and in the non-inference endpoints clients call.

Two of them cost money. The catalog carried no claude-opus-5 or
claude-sonnet-5, so an operator could not authorise the models coding agents
default to — those requests denied as not-routable, or priced at zero where a
catch-all carried them. And gateway records pin ParserID "openai" while the
same record serves /v1/messages, so Anthropic responses were read with the
OpenAI parser, which never looks at message_start where input tokens live:
input metered as roughly zero on every stream and cost was skipped entirely.

The rest fix requests refused for structural rather than policy reasons: model
discovery denied for every account with a model allowlist, token counting
denied on Bedrock and mis-parsed on Vertex, startup probes refused and written
into the access log at every session start, and denials rendered in a shape no
LLM client parses. Two changes are additive by design — the deny body keeps
every field it had and adds the vendor's error object alongside, and body-level
identity injection is now gated on the request's dialect so it stops sending
OpenAI-shape fields into Anthropic bodies that reject them.

The end-to-end work turned up one more: the discovery filter treated any slash
in a model id as a gateway prefix, which would have dropped every self-hosted
"Qwen/..." model from the picker.
2026-08-23 20:02:33 +02:00
Bethuel Mmbaga
e206f8827d [management] Suppress staticcheck warnings for deprecated proto fields (#7261) 2026-08-20 16:20:18 +02:00
dmitri-netbird
a144e8c144 [client, management] switch to go.uber.org/mock (#7253)
* switch to go.uber.org/mock/gomock

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* updated go:generate commands + regenerated mocks

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* update go:generate mockgen commands

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* removed duplicate import

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* fix go:generate

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

---------

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
2026-08-20 11:53:19 +02:00
Zoltan Papp
070a0a7bf1 [client, android] Handle network changes without restarting the engine (#7144)
On network changes the client restarted the whole engine. That is heavy-handed and slow: it tears down working state to recover from a transition the engine could handle itself. This replaces the restart with proper network event handling.

Suspend the retry loops while no network is available. Instead of burning through backoff intervals against an unreachable network, the reconnection loops park until the OS reports a usable network again.

Reconnect immediately on a network switch. When the OS hands us a new network, connections bound to the old one are swept and re-dialed right away, rather than waiting for a timeout to notice they are dead.
2026-08-19 10:05:12 +02:00
Misha Bragin
93e97f4bf1 [doc] Agent network docs update (#7020)
* [docs] Update agent-network docs for management-owned pricing

  The docs still described the retired proxy-side pricing: pricing.Loader,
  pricing_path, MiddlewareDataDir, embedded defaults_pricing.yaml, and the
  symlink-safe Unix loader. Rewrite them for the current design — management
  synthesizes the whole table and ships it in cost_meter's ConfigJSON, so the
  proxy carries no price list and has nothing to reload.
2026-08-15 19:31:49 +02:00
Jack Carter
58c09ead21 [management] Document mutual exclusivity of policy rule ports and port_ranges (#7158) 2026-08-12 20:39:06 +02:00
Brad Ison
ebfdf7d7b8 [management] Rework Agent Network endpoint identity and settings bootstrap (#7085)
Store the per-account gateway endpoint as {domain, proxy_address} with a
global unique index on the full hostname; dedicated = (domain ==
proxy_address). Bootstrap becomes an explicit POST carrying exactly one
of proxy_address (server allocates an adjective-noun label beneath it)
or endpoint (claimed verbatim, address-first); provider create loses its
bootstrap side effect. PUT is a full replace with every field required —
the immutable identity fields must be echoed unchanged and a mismatch is
rejected with 422. A guarded DELETE releases the endpoint: refused with
412 while providers exist or a proxy is actively serving the endpoint
hostname (matched case-insensitively); re-creating bootstraps fresh. A
self-addressed pin excludes its address from the account's cluster allow
list, and the live mapping update path now addresses the serving proxy
from the synthesized service. Existing rows are migrated on all three
store engines.
2026-08-10 19:06:55 +02:00
Viktor Liu
e8671a811d [client, relay] Migrate relay QUIC tracer to qlog and bump quic-go to 0.59.1 (#7124) 2026-08-10 17:41:31 +02:00
Viktor Liu
5584f8ef0a [client] Add strict anonymization level and MAC anonymization to debug bundles (#7102) 2026-08-10 11:27:20 +02:00
Riccardo Manfrin
19a6cedfff [relay] randomize the relay reconnect backoff (#7067)
## Describe your changes

The relay client's reconnect backoff was constructed without a
`RandomizationFactor`
([guard.go:156-165](https://github.com/netbirdio/netbird/blob/main/shared/relay/client/guard.go#L156-L165)),
so it kept the zero value: every client that lost the same relay server
retried on the identical 2/4/8/16/32/60, potentially in waves.

It was the only exponential backoff in the codebase without a
randomization factor.

Use `backoff.DefaultRandomizationFactor`, as random factor.

## Issue ticket number and link

No public issue. Found while reviewing the relay reconnect path for the
client-metrics review:
22k relay reconnection events in 24h, and the shared transport's own
retry schedule was
identical across all clients.

## Stack

<!-- branch-stack -->

### Checklist
- [x] Is it a bug fix
- [ ] Is a typo/documentation fix
- [ ] Is a feature enhancement
- [ ] It is a refactor
- [x] Created tests that fail without the change (if possible)

> By submitting this pull request, you confirm that you have read and
agree to the terms of the [Contributor License
Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md).

## Documentation
Select exactly one:

- [ ] I added/updated documentation for this change
- [x] Documentation is **not needed** for this change (explain why)

Internal retry-timing change with no user-visible surface: no CLI flag,
configuration option
or API field is added or altered, and the mean reconnect delay is
unchanged.

### Docs PR URL (required if "docs added" is checked)
Paste the PR link from https://github.com/netbirdio/docs here:

N/A


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved reconnect timing to distribute repeated connection attempts
more evenly and reduce synchronized retry spikes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-05 17:01:21 +02:00
Maycon Santos
bc7a15ab71 [management] Align agent-network API contracts for API clients (#7026)
## Describe your changes

Work on the Terraform provider (terraform-provider-netbird #177–#183)
surfaced places where the agent-network API broke its own contracts or
deviated from the conventions the rest of the management API follows,
forcing client-side workarounds.

Settings reads now follow the settings-endpoint convention: GET always
answers with a JSON object. Before bootstrap it returns the defaults
with an empty cluster/subdomain/endpoint (previously 200 with a JSON
`null` body, while the spec said 404). The settings PUT can bootstrap
the account by carrying a `cluster` — previously the row could only come
into existence through the first provider create, and a settings-first
setup was impossible; a differing cluster on a bootstrapped account is
rejected instead of silently ignored. PUT remains full-state.

The provider PUT schema promised omit-preserves semantics for several
operator-editable fields that the handler never delivered (it builds the
row from the request, like every other update handler). The schema
wording now matches the shipped full-state behavior; only the api_key
(secret) and session keys stay preserved by the manager. Identity
headers are always present in provider responses so an explicitly
cleared value round-trips as an empty string.

The Go REST client gains the full agent-network surface (catalog,
providers, policies, guardrails, budget rules, settings), including a
shim translating the legacy 200+`null` settings body from older servers
into an `IsNotFound` error.

Note for reviewers: the dashboard special-cased the `null` settings
body; it needs a small follow-up for the new defaults response (in
progress).
2026-08-04 01:59:09 +02:00
Zoltan Papp
075b319fb3 [client, android] Pull fresh TUN settings on Android rebuild (#6991)
## Describe your changes

Pull fresh TUN settings on Android rebuild instead of push

The Android TUN rebuild consumed state pushed through notifications and
a Java-side snapshot, and both sources were unreliable. The DNS
search-domain notifier fired OnNetworkChanged with an empty string,
which the rebuild handler treated as the new route list, so any search
domain change rebuilt the TUN with zero routes and cut all tunnel
traffic. The rebuild also reused the search domains cached at the last
establish, so search domain updates never reached the TUN at runtime.

Make the notification a pure trigger and let the Java side pull a fresh
snapshot instead. Expose GetTunSettings on the Android SDK client: it
returns the current TUN route ranges, derived on demand by the route
manager from the client routes, the exit-node selection and the fake IP
blocks, together with the DNS search domains. The route notifier keeps
only its last-announced baseline to suppress triggers for unchanged
syncs; the TUN route state is owned by the route manager. SearchDomains
now locks the DNS server mutex since the pull arrives from a Java
thread.

Requires the matching android-client change that switches recreateTUN to
the pull API.

## Issue ticket number and link

## Stack

<!-- branch-stack -->

### Checklist
- [x] Is it a bug fix
- [ ] Is a typo/documentation fix
- [ ] Is a feature enhancement
- [ ] It is a refactor
- [ ] Created tests that fail without the change (if possible)
- [ ] This change does **not** modify the public API, gRPC protocols,
functionality behavior, CLI / service flags, or introduce a new feature
— **OR** I have discussed it with the NetBird team beforehand (link the
issue / Slack thread in the description). See
[CONTRIBUTING.md](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTING.md#discuss-changes-with-the-netbird-team-first).

> By submitting this pull request, you confirm that you have read and
agree to the terms of the [Contributor License
Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md).

## Documentation
Select exactly one:

- [ ] I added/updated documentation for this change
- [x] Documentation is **not needed** for this change (explain why)

### Docs PR URL (required if "docs added" is checked)
Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
  - Added access to current TUN route ranges and DNS search domains.
- TUN settings are returned in a mobile-friendly format for easier
integration.

- **Improvements**
  - Route changes are detected and synchronized more reliably.
- Current routing information now reflects active routes, including
supported fake-IP ranges.
- Simplified network initialization for more consistent startup
behavior.

- **API Changes**
- Removed the obsolete network-map retrieval method from the management
client interface.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 18:23:02 +02:00
Pascal Fischer
f9b412228e [management] fix handling of empty network map during decode and encode (#6987) 2026-08-03 13:20:53 +02:00
Misha Bragin
0780a806f2 [management, proxy] Management-owned LLM pricing: file-backed defaults + (#6965) 2026-07-31 20:52:56 +02:00
Viktor Liu
b3f9b82442 [management] Force routing-peer DNS resolution for reverse-proxy domain targets (#6872) 2026-07-28 14:45:57 +02:00
Maycon Santos
4f6247b5c3 [management, proxy] Add prompt-cache token and cost accounting to agent network usage (#6900)
Co-authored-by: braginini <bangvalo@gmail.com>
2026-07-26 21:42:41 +02:00
Riccardo Manfrin
b65ec8b68a [client] Restores lost backup.Reset from #4935 (#6883)
## Describe your changes

Restore the management gRPC client's backoff reset after a stream
connects.

This is a regression: PR #4935 originally added this reset; it was then
lost in
commit `58daa674e` during the `withMgmtStream` refactor (Sync/Job
unification).

Compared to before the reset was done AFTER receiveEvents, whereas 
now it's done before. 

Now should cover for Sync and Job (which didn't exist in #4935. Hold for
long living stream that breaks.

Reset prevents two things

1. long living conns going wrong from waiting a long backoff time window
before to drive reconn
2. past MaxElapsedTime (3months) long lived conns failures from being
treated as "unrecoverable" (hence triggering an full restart of the
engine)

## Issue ticket number and link

Internal support case (customer agents lost data-plane connectivity
during a
management maintenance/release window). No public issue. Regression
introduced
in commit `58daa674e`, which removed the `backOff.Reset()` added by PR
#4935.

## Stack

<!-- branch-stack -->

### Checklist
- [x] Is it a bug fix
- [ ] Is a typo/documentation fix
- [ ] Is a feature enhancement
- [ ] It is a refactor
- [ ] Created tests that fail without the change (if possible)

> By submitting this pull request, you confirm that you have read and
agree to the terms of the [Contributor License
Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md).

## Documentation
Select exactly one:

- [ ] I added/updated documentation for this change
- [x] Documentation is **not needed** for this change (explain why)

Internal reconnection-behavior fix in the management gRPC client. No
public
NetBird CLI, API, or configuration surface changes.

### Docs PR URL (required if "docs added" is checked)
Paste the PR link from https://github.com/netbirdio/docs here:

N/A

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/netbirdio/codesmith/netbird/pr/6883"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img
alt="View with [code]smith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a>
<a
href="https://backend.blacksmith.sh/track/enable-autofix?expires=1787484622&installation_model_id=427504&pr_number=6883&repository=netbirdio%2Fnetbird&return_to=https%3A%2F%2Fgithub.com%2Fnetbirdio%2Fnetbird%2Fpull%2F6883&signature=525b08edbcb94ee6f4ae4226fb1fe8ddb829caa7d4489e8efa639770af9dccdf"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img
alt="Autofix with [code]smith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you
need. Autofix is disabled.</sup>

<!-- codesmith:autofix:disabled -->
<!-- /codesmith:footer -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved management stream retry behavior.
* Retry delays now reset after a stream is successfully established,
helping subsequent connection attempts recover more quickly.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-24 13:53:53 +02:00
Pascal Fischer
31ed241a1a [management] component types (#6866) 2026-07-23 11:37:09 +02:00
dmitri-netbird
8435682ac8 [client, management] offload client config generation to the client (#6711)
Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
Co-authored-by: crn4 <vladimir@netbird.io>
Co-authored-by: pascal <pascal@netbird.io>
2026-07-22 18:20:27 +02:00
Maycon Santos
d64e9542eb [proxy] Bedrock cost-allocation metadata + per-provider metadata_disabled (#6791) 2026-07-20 14:45:50 +02:00
Viktor Liu
3fb26d458e [relay] Remove deprecated Hello handshake and gob token decode (#6783) 2026-07-20 14:13:40 +02:00
dmitri-netbird
877e889250 [management] fix fetching of missing settings in GetAccount call (#6800)
## Describe your changes

## Issue ticket number and link

## Stack

<!-- branch-stack -->

### Checklist
- [x] Is it a bug fix
- [ ] Is a typo/documentation fix
- [ ] Is a feature enhancement
- [ ] It is a refactor
- [ ] Created tests that fail without the change (if possible)
- [x] This change does **not** modify the public API, gRPC protocols,
functionality behavior, CLI / service flags, or introduce a new feature
— **OR** I have discussed it with the NetBird team beforehand (link the
issue / Slack thread in the description). See
[CONTRIBUTING.md](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTING.md#discuss-changes-with-the-netbird-team-first).

> By submitting this pull request, you confirm that you have read and
agree to the terms of the [Contributor License
Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md).

## Documentation
Select exactly one:

- [ ] I added/updated documentation for this change
- [x] Documentation is **not needed** for this change (explain why)

### Docs PR URL (required if "docs added" is checked)
Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/netbirdio/codesmith/netbird/pr/6800"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img
alt="View with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a>
<a
href="https://backend.blacksmith.sh/track/enable-autofix?expires=1786797566&installation_id=146802194&pr_number=6800&repository=netbirdio%2Fnetbird&return_to=https%3A%2F%2Fgithub.com%2Fnetbirdio%2Fnetbird%2Fpull%2F6800&signature=36a7053e1029e5de1d496fbd9c428a1745d0ec22b3e6479d64aafb1b8350b0ef"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img
alt="Autofix with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>/codesmith</code> with what you
need. Autofix is disabled.</sup>

<!-- codesmith:autofix:disabled -->
<!-- /codesmith:footer -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Ensure account settings are fully preserved through save/load,
including automatic update and peer exposure preferences.

* **Tests**
* Added coverage to verify account settings remain unchanged after
database persistence and retrieval (skipped on Windows due to SQLite
limitations).
* Introduced deterministic test-data population helpers to reliably set
struct fields for deeper settings verification.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
2026-07-17 10:38:43 +02:00
Riccardo Manfrin
5343402385 [client, relay] Increase early-message buffer cap to 10000 to avoid dropping relayed handshakes 2026-07-13 22:46:03 +02:00
Maycon Santos
831325d6e2 [management] require dashboard_features.agent_network when enabling agent_network_only (#6750)
Adds a settings constraint: enabling `agent_network_only` requires `dashboard_features.agent_network` to be `true` in the same account update. Without the Agent Network menu flag, a focused account that later turns the focused view off would lose access to the Agent Network menu entirely, so the two must be set together.

The check runs in `updateAccountRequestSettings` against the parsed request state: if the resulting settings have `agent_network_only == true` but `dashboard_features.agent_network` is not `true`, the update is rejected with `status.InvalidArgument` (HTTP 422) before anything is persisted.

The OpenAPI field descriptions for `agent_network_only` and `dashboard_features.agent_network` document the requirement. Only the descriptions changed — `required` and the schema `$ref` are untouched — and `types.gen.go` was regenerated from the spec (diff is the two comment lines).
2026-07-13 17:28:19 +02:00
Maycon Santos
ecd398d895 [management] Add dashboard_features account setting (#6742)
Introduce a nullable dashboard_features object on account settings, serialized
to a single JSON column so new dashboard sections can be added without schema
changes. Starts with agent_network (show the Agent Network menu for an account
without the deployment flag). Wires the API handler mapping, the pgx GetAccount
loader, and adds store round-trip and handler tests.
2026-07-12 21:16:37 +02:00
Maycon Santos
aa92ad3fb1 [management] Add agent_network_only account setting (#6736)
* [management] Add agent_network_only account setting

* [management] Load agent_network_only in pgx account loader and cover persistence
2026-07-12 14:46:08 +02:00
Sufiyan Khan
fd94fdb42b [management] fix duplicate operationId in OpenAPI spec (#6734) 2026-07-12 14:15:55 +02:00
Pascal Fischer
2560c6bd6c [management] add traffic filters for source and dest id (#6697) 2026-07-09 14:37:31 +02:00
Viktor Liu
96ac15d292 [client] Fix js relay WebSocket close, raise RDP dial timeout, adjust WASM log levels (#6684) 2026-07-09 13:21:08 +02:00
Theodor Midtlien
b7bbb44286 [client] Merge v0.74.x branch (#6700)
* [client] Update gopsutil to v4 (#6688)
* [client] Fix hanging status command during relay dial (#6694)

---------

Co-authored-by: Maycon Santos <mlsmaycon@gmail.com>
2026-07-08 17:52:50 +02:00
dmitri-netbird
47352e6e45 [client] introduce client-side event aggregation (#6627)
* added an implementation of aggregating memory store

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* initial support for aggregation of events

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* added tcp-aggregation test

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* added manager integration test

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* added tracking of the number of start-, drop, and end-events in an aggregation window

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* fixes based on sonarcube checks

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* regenerated proto files

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* removed inadvertenly added google proto files

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* pacifying linter

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* update test to validate event aggregation over tcp, udp, icmp, and icmpv6

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* updated event aggregation test

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* regenerate protobufs with expected versions of protoc and protoc-gen-go

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* remove protoc/protoc-gen headers from flow_grpc.pb.go

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* updated openapi spec

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* updated openapi NetworkTrafficEvent spec, regenerated types

Signed-off-by: Dmitri <dmitri.external@netbird.io>

* respond to feedback

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* fixed an issue with how we track events that shouldn't be aggregated

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* fixed mapping of events to protobuf

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* icmp code values in aggregated events do not matter

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* regenerate openapi types

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* added a comment re: unbounded unacked events

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* reset aggregated event type to unknown

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* fix event aggregation test

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* used the source port of the earliest event

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* add tracking of window starts and ends

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* updated openapi spec

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* reverted changes to generate.sh

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* cleanup handling of not-aggregated events + test

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* responded to feedback + small fixes

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* small fix in a test

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* another test

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* force setting non-empty rule id on aggregated events

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* fixed a couple of issues flagged by coderabbit

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* fix spelling

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

* handle exhausted retry backoffs

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>

---------

Signed-off-by: Dmitri <dmitri.external@netbird.io>
Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
2026-07-06 16:04:26 +02:00
Maycon Santos
91acb8147c [management,client] 0.75.0 release with new desktop UI (#6473)
- **Wails v3 application** (`client/ui`) with a React + TypeScript + Tailwind frontend replacing the Fyne UI: main connection view, exit-node switcher, networks/peers browser with detail panels, profile management, settings (general, network, SSH, security, troubleshooting, appearance), debug-bundle creation, and a first-run welcome flow.
- **Internationalization**: go-i18n bundle with 9 locales (en, de, es, fr, hu, it, pt, ru, zh-CN) shared between the tray and the frontend.
- **New system tray** implementation with per-platform theme-aware icons, including a native XEmbed host for Linux (`xembed_tray_linux.c`) and a Linux theme watcher.
- **Session handling**: auth session watcher (`client/internal/auth/sessionwatch`), pending login flow, session-expiration dialog and tray notifications, and `netbird login` improvements.
- **Daemon API extensions** (`daemon.proto`): status stream subscription, event stream, networks/exit-node selection endpoints, and richer full status — with probe throttling on the daemon side to protect against UI-driven request storms.
- **UI preferences store** persisted per profile, autostart management via the daemon (single source of truth in HKCU on Windows).
- **Build system**: Taskfile-based builds per platform (macOS, Linux, Windows), Docker cross-compilation images, MSIX/NSIS/nfpm/AppImage packaging, and a new `frontend-ui` CI workflow.

Co-authored-by: Zoltan Papp <zoltan.pmail@gmail.com>
Co-authored-by: Eduard Gert <kontakt@eduardgert.de>
Co-authored-by: braginini <bangvalo@gmail.com>
Co-authored-by: Pascal Fischer <32096965+pascal-fischer@users.noreply.github.com>
Co-authored-by: riccardom <riccardomanfrin@gmail.com>
2026-07-06 13:47:16 +02:00
Riccardo Manfrin
8e3b284f4b [client] Increase mgmt grpc buff size to 16MB (#6641) 2026-07-02 17:50:18 +02:00
Viktor Liu
1d8b5f6e5c [client] Make lazy connections opt-out via NB_LAZY_CONN (#6617) 2026-07-02 10:58:16 +02:00
Maycon Santos
eb422a5cd3 [management,proxy] Add per-provider skip_tls_verification for agent-network (#6630)
* [management,proxy] Add per-provider skip_tls_verification for agent-network

Let agent-network providers opt into skipping upstream TLS verification for
self-hosted / internal gateways behind a private or self-signed cert.

- provider: add SkipTLSVerification (persisted via AutoMigrate) with
  request/response mapping (nil on update preserves, explicit false clears).
- openapi: skip_tls_verification on the provider request + response; types
  regenerated.
- synthesizer: carry the flag into the llm_router route config so it reaches
  the proxy.
- proxy: llm_router sets it on the UpstreamRewrite mutation, and the reverse
  proxy applies roundtrip.WithSkipTLSVerify per selected route when forwarding
  upstream (the router dials per provider, so a per-target flag alone wouldn't
  cover it).
- tests: synthesizer route config carries the flag, router rewrite propagates
  it, and the request/response round-trip incl. update semantics.

* [e2e] Validate per-provider skip_tls_verification end to end

Add a self-signed HTTPS upstream (nginx) to the harness and a test that
provisions two providers on that same upstream — one with
skip_tls_verification=true, one false — behind one proxy + client. The
skip=true provider's chat reaches the upstream (200); the skip=false
provider's fails the TLS handshake (5xx). Same upstream, opposite outcome,
which proves the flag is honoured per provider (a single target-level flag
could not, since all of an account's providers share one synthesised
target).

* [e2e] WaitProxyPeer: require >=1 connected peer, not exact 1/1

Each proxy container registers a fresh WireGuard key and its peer is not
removed on teardown, so proxy peers from earlier tests linger in the
account as disconnected. WaitProxyPeer matched the exact string
"1/1 Connected", which failed once a second proxy-using test ran in the
same package (status "1/2"). Parse the "Peers count: X/Y Connected" line
and wait for X>=1 instead: only the live proxy can be connected, and the
caller's subsequent chat is the real end-to-end assertion. Fixes the CI
failure of TestProviderSkipTLSVerification (runs after TestProvidersMatrix).
2026-07-01 20:43:15 +02:00
Riccardo Manfrin
0aa0f7c76b [client] wire client -> mgmt is healthy check to proper gRPC API (#6421) 2026-07-01 19:10:50 +02:00
Zoltan Papp
980598ed4a [management, client] Add management-controlled client metrics push (#5886)
* [management, client] Add management-controlled client metrics push

Allow enabling/disabling client metrics push from the dashboard via
account settings instead of requiring env vars on every client.

- Add MetricsConfig proto message to NetbirdConfig
- Add MetricsPushEnabled to account Settings (DB-persisted)
- Expose metrics_push_enabled in OpenAPI and dashboard API handler
- Populate MetricsConfig in sync and login responses
- Client dynamically starts/stops push based on management config
- NB_METRICS_PUSH_ENABLED env var overrides management when explicitly set
- Add activity events for metrics push enable/disable

* Remove log line

* [management] Fix peer update test for MetricsConfig in NetbirdConfig

Update TestUpdateAccountPeers assertions: NetbirdConfig is no longer
nil in peer update responses since it now carries MetricsConfig even
when STUN/TURN config is absent.

* Regenerate proto files with protoc v7.34.1

* [management] Read metrics push setting in Postgres account query

getAccountPgx omitted settings_metrics_push_enabled from its hand-written
SELECT and Scan, so the toggle was always read back as false on Postgres
and never reached clients.

* [client] Fix metrics push getting stuck off after engine restart

Engine restarts (backoff retries within the same login session) cancel
e.ctx, which the push goroutine's lifetime was tied to. The goroutine
died silently but ClientMetrics.push stayed non-nil since only an
explicit stop clears it, so the next UpdatePushFromMgm call saw a
"push already running" state and never restarted it.

Give the Engine its own metricsCtx sourced from ConnectClient.ctx,
which outlives engine restarts, so handleMetricsUpdate stops tying the
push to the wrong-scoped context. Additionally make ClientMetrics.push
an atomic.Pointer that the push goroutine clears via CompareAndSwap on
exit, so the tracked state can never drift from the goroutine's actual
lifetime regardless of which context a future caller passes in.

* [management] Regenerate OpenAPI types with oapi-codegen v2.7.1

types.gen.go was regenerated with a stale local v2.6.0 binary,
causing the CI git-diff check against generate.sh's pinned v2.7.1
to fail.
2026-07-01 14:50:25 +02:00