Merge remote-tracking branch 'origin/main' into file-share

This commit is contained in:
Zoltan Papp
2026-09-05 19:58:31 +02:00
13 changed files with 190 additions and 137 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
if ! which realpath >/dev/null 2>&1; then
+2 -2
View File
@@ -1,2 +1,2 @@
#!/bin/bash
protoc -I testprotos/ testprotos/testproto.proto --go_out=.
#!/usr/bin/env bash
protoc -I testprotos/ testprotos/testproto.proto --go_out=.
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
if ! which realpath > /dev/null 2>&1
@@ -19,6 +19,14 @@ func TestGetNetworkRouters(t *testing.T) {
execQuery(t, ctx,
`insert into network_routers (id, account_id, public_id, peer, network_id, masquerade, metric, enabled, peer_groups)
VALUES('test-nr-id-2','account-1','public-id-2','','network-id-2',TRUE,333,TRUE,'["group-two-resources-id","group-no-resources-id"]')`)
// empty peer_groups
execQuery(t, ctx,
`insert into network_routers (id, account_id, public_id, peer, network_id, masquerade, metric, enabled, peer_groups)
VALUES('test-nr-id-3','account-1','public-id-3','peer-id-3','network-id-3',TRUE,999,TRUE,'[]')`)
// nil peer_groups
execQuery(t, ctx,
`insert into network_routers (id, account_id, public_id, peer, network_id, masquerade, metric, enabled, peer_groups)
VALUES('test-nr-id-4','account-1','public-id-4','peer-id-4','network-id-4',TRUE,999,TRUE,null)`)
routers, err := conn(t, ctx).GetNetworkRouters(ctx, "account-1")
assert.NoError(t, err)
@@ -30,4 +38,8 @@ func TestGetNetworkRouters(t *testing.T) {
map[string]*nmdata.NetworkRouter{
"peer-id-2": {PublicID: "public-id-2", Masquerade: true, Metric: 333, Enabled: true, PeerGroups: []string{"group-two-resources-id", "group-no-resources-id"}},
"peer-id-3": {PublicID: "public-id-2", Masquerade: true, Metric: 333, Enabled: true, PeerGroups: []string{"group-two-resources-id", "group-no-resources-id"}}})
assert.Equal(t, routers["network-id-3"],
map[string]*nmdata.NetworkRouter{"peer-id-3": {PublicID: "public-id-3", Masquerade: true, Metric: 999, Enabled: true, PeerGroups: []string{}}})
assert.Equal(t, routers["network-id-4"],
map[string]*nmdata.NetworkRouter{"peer-id-4": {PublicID: "public-id-4", Masquerade: true, Metric: 999, Enabled: true, PeerGroups: nil}})
}
@@ -21,6 +21,14 @@ func TestGetAllowedUsers(t *testing.T) {
execQuery(t, ctx,
`insert into users (id, name, account_id, auto_groups, blocked, is_service_user)
VALUES('user-3','user-3','account-1','["group-two-resources-id"]',false,false)`)
// empty auto_groups; shouldn't error out
execQuery(t, ctx,
`insert into users (id, name, account_id, auto_groups, blocked, is_service_user)
VALUES('user-31','user-31','account-1','[]',false,false)`)
// null auto_groups; shouldn't error out
execQuery(t, ctx,
`insert into users (id, name, account_id, auto_groups, blocked, is_service_user)
VALUES('user-32','user-32','account-1',null,false,false)`)
// shouldn't be included as it's blocked
execQuery(t, ctx,
`insert into users (id, name, account_id, auto_groups, blocked, is_service_user)
@@ -43,15 +51,17 @@ func TestGetAllowedUsers(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, userIdx, map[string]struct{}{
"user-1": {},
"user-2": {},
"user-3": {},
"user-1": {},
"user-2": {},
"user-3": {},
"user-31": {},
"user-32": {},
})
assert.Equal(t, groupIdToUserIds, map[string][]string{
"group-one-resource-id": {"user-1", "user-2"},
"group-two-resources-id": {"user-2", "user-3"},
"all-group-1": {"user-1", "user-2", "user-3"},
"all-group-2": {"user-1", "user-2", "user-3"},
"all-group-3": {"user-1", "user-2", "user-3"},
"all-group-1": {"user-1", "user-2", "user-3", "user-31", "user-32"},
"all-group-2": {"user-1", "user-2", "user-3", "user-31", "user-32"},
"all-group-3": {"user-1", "user-2", "user-3", "user-31", "user-32"},
})
}
@@ -1,120 +0,0 @@
package networkmapdb_test
import (
"context"
"net/netip"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
networkmap_pgsql "github.com/netbirdio/netbird/management/internals/network_map_db/pgsql"
networkmap_sqlite "github.com/netbirdio/netbird/management/internals/network_map_db/sqlite"
routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types"
nbpeer "github.com/netbirdio/netbird/management/server/peer"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/testutil"
"github.com/netbirdio/netbird/management/server/types"
)
// newEngineStores opens both stores on the selected engine's database.
func newEngineStores(t *testing.T) (store.Store, networkmapdb.NetworkMapDBStore) {
t.Helper()
ctx := context.Background()
switch engine := types.Engine(os.Getenv("NETBIRD_STORE_ENGINE")); engine {
case types.PostgresStoreEngine:
cleanup, dsn, err := testutil.CreatePostgresTestContainer()
require.NoError(t, err, "start postgres test container")
t.Cleanup(cleanup)
accountStore, err := store.NewPostgresqlStore(ctx, dsn, nil, false)
require.NoError(t, err, "connect account store")
t.Cleanup(func() { _ = accountStore.Close(ctx) })
nmStore, err := networkmap_pgsql.NewPostgresqlStore(ctx, dsn)
require.NoError(t, err, "connect networkmap store")
t.Cleanup(func() { nmStore.Pool.Close() })
return accountStore, nmStore
case types.SqliteStoreEngine, "":
dataDir := t.TempDir()
accountStore, err := store.NewSqliteStore(ctx, dataDir, nil, false)
require.NoError(t, err, "open account store")
t.Cleanup(func() { _ = accountStore.Close(ctx) })
nmStore, err := networkmap_sqlite.NewSqliteStore("store.db", dataDir)
require.NoError(t, err, "open networkmap store")
t.Cleanup(func() { _ = nmStore.Db.Close() })
return accountStore, nmStore
default:
t.Skipf("networkmap store does not support engine %q", engine)
return nil, nil
}
}
// Peer-based routers must survive the network-map read on every engine.
func TestGetNetworkRouters_ServesPeerBasedRouters(t *testing.T) {
ctx := context.Background()
accountStore, nmStore := newEngineStores(t)
const (
accountID = "acc-nmap-routers"
groupID = "grp-router-members"
memberID = "peer-member"
)
// Postgres enforces the groups-to-accounts FK that SQLite ignores.
require.NoError(t, accountStore.SaveAccount(ctx, &types.Account{
Id: accountID,
Peers: map[string]*nbpeer.Peer{
memberID: {
ID: memberID,
AccountID: accountID,
Key: memberID + "-key",
IP: netip.MustParseAddr("100.64.0.10"),
Status: &nbpeer.PeerStatus{},
},
},
Groups: map[string]*types.Group{
groupID: {
ID: groupID,
AccountID: accountID,
Name: "router members",
Issued: types.GroupIssuedAPI,
Peers: []string{memberID},
},
},
}), "seed the account the routers belong to")
routers := []*routerTypes.NetworkRouter{
{ID: "router-peer-nil", AccountID: accountID, NetworkID: "net-peer-nil", PublicID: "pub-peer-nil", Peer: "peer-direct-nil", Enabled: true, Metric: 9999},
{ID: "router-peer-empty", AccountID: accountID, NetworkID: "net-peer-empty", PublicID: "pub-peer-empty", Peer: "peer-direct-empty", PeerGroups: []string{}, Enabled: true, Metric: 9999},
{ID: "router-group", AccountID: accountID, NetworkID: "net-group", PublicID: "pub-group", PeerGroups: []string{groupID}, Enabled: true, Metric: 9999},
}
for _, router := range routers {
require.NoError(t, accountStore.CreateNetworkRouter(ctx, router))
}
tx, err := nmStore.BeginTx(ctx)
require.NoError(t, err, "begin networkmap read transaction")
t.Cleanup(func() { _ = tx.RollbackTx(ctx) })
got, err := tx.GetNetworkRouters(ctx, accountID)
require.NoError(t, err, "read network routers")
assert.Contains(t, got, "net-peer-nil",
"a router referencing an individual peer (peer_groups stored as NULL) must reach the network map")
assert.Contains(t, got["net-peer-nil"], "peer-direct-nil",
"the individual-peer router must be keyed by its peer")
assert.Contains(t, got, "net-peer-empty",
"a router referencing an individual peer (peer_groups stored as '[]') must reach the network map")
assert.Contains(t, got["net-peer-empty"], "peer-direct-empty",
"the individual-peer router must be keyed by its peer")
assert.Contains(t, got, "net-group", "a group router must reach the network map")
assert.Contains(t, got["net-group"], memberID,
"the group router must fan out to the group's member peers")
}
@@ -15,6 +15,7 @@ const (
from zones
left join records as r on r.zone_id = zones.id
where zones.account_id=$1 and zones.enabled
order by zones.id
`
)
@@ -42,17 +42,20 @@ func (sc *SqliteStoreConn) GetAllowedUsers(ctx context.Context, accountId string
userIdIdx := make(map[string]struct{})
groupIdToUserIds := make(map[string][]string)
for _, user := range users {
for _, allgid := range allGroupIds {
groupIdToUserIds[allgid] = append(groupIdToUserIds[allgid], user.ID)
}
userIdIdx[user.ID] = struct{}{}
autogroups := make([]string, 0)
if user.AutoGroups == nil {
continue
}
if err := json.Unmarshal(user.AutoGroups, &autogroups); err != nil {
return nil, nil, err
}
userIdIdx[user.ID] = struct{}{}
for _, groupId := range autogroups {
groupIdToUserIds[groupId] = append(groupIdToUserIds[groupId], user.ID)
}
for _, allgid := range allGroupIds {
groupIdToUserIds[allgid] = append(groupIdToUserIds[allgid], user.ID)
}
}
return userIdIdx, groupIdToUserIds, nil
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
if ! which realpath > /dev/null 2>&1
+99
View File
@@ -6443,6 +6443,44 @@ components:
- enable_prompt_collection
- redact_pii
- access_log_retention_days
AgentNetworkManagedProxy:
type: object
description: A NetBird-managed Agent Network gateway deployment.
properties:
id:
type: string
description: Managed proxy deployment ID.
example: "d1m3kebd9pcs0c1pnu7g"
state:
type: string
description: Derived deployment state. `provisioning` until the gateway is rolled out and connected, `ready` while the gateway actively serves the endpoint, `failed` when the rollout reported a failure.
enum: [ "provisioning", "ready", "failed" ]
example: "ready"
endpoint:
type: string
description: The account's gateway hostname.
example: "brave-otter.gateway.netbird.io"
region:
type: string
description: Region of the cluster hosting the deployment.
example: "us-east"
message:
type: string
description: Failure detail reported by the rollout. Only set when state is `failed`.
required:
- id
- state
- endpoint
AgentNetworkManagedProxyConflict:
type: object
description: Conflict body returned when the account already has an Agent Network endpoint that managed provisioning does not own, naming that endpoint.
properties:
endpoint:
type: string
description: The Agent Network endpoint already assigned to the account.
example: "llm.example.com"
required:
- endpoint
AgentNetworkBudgetRule:
type: object
description: Account-level budget rule. A limit-only rule bound to groups and/or users that applies across all policies as a min-wins ceiling. Empty targets means it applies to every caller.
@@ -13531,6 +13569,67 @@ paths:
"$ref": "#/components/responses/not_found"
'500':
"$ref": "#/components/responses/internal_error"
/api/integrations/agent-network/managed-proxy:
post:
summary: Provision a managed Agent Network gateway
description: Starts provisioning of a NetBird-managed Agent Network gateway for the account, allocating its endpoint under the managed zone on the first call. Idempotent — answers 202 when this call started (or, after a failure, restarted) provisioning and 200 when a deployment already exists, reporting current state either way. Returns 409 when the account already has an Agent Network endpoint that managed provisioning does not own, and 503 when endpoint allocation is temporarily exhausted.
tags: [ Agent Network ]
security:
- BearerAuth: [ ]
- TokenAuth: [ ]
responses:
'200':
description: A managed gateway deployment already exists; reports its current state.
content:
application/json:
schema:
$ref: '#/components/schemas/AgentNetworkManagedProxy'
'202':
description: Provisioning started, or restarted after a reported failure
content:
application/json:
schema:
$ref: '#/components/schemas/AgentNetworkManagedProxy'
'401':
"$ref": "#/components/responses/requires_authentication"
'403':
"$ref": "#/components/responses/forbidden"
'409':
description: The account already has an Agent Network endpoint not owned by managed provisioning
content:
application/json:
schema:
$ref: '#/components/schemas/AgentNetworkManagedProxyConflict'
'500':
"$ref": "#/components/responses/internal_error"
'503':
description: Endpoint allocation is temporarily exhausted; retry later
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
get:
summary: Retrieve managed Agent Network gateway status
description: Reports the account's managed gateway deployment and its derived state. Returns 404 when the account has no managed deployment.
tags: [ Agent Network ]
security:
- BearerAuth: [ ]
- TokenAuth: [ ]
responses:
'200':
description: The account's managed gateway deployment
content:
application/json:
schema:
$ref: '#/components/schemas/AgentNetworkManagedProxy'
'401':
"$ref": "#/components/responses/requires_authentication"
'403':
"$ref": "#/components/responses/forbidden"
'404':
"$ref": "#/components/responses/not_found"
'500':
"$ref": "#/components/responses/internal_error"
/api/agent-network/access-logs:
get:
summary: List Agent Network access logs
+48
View File
@@ -77,6 +77,27 @@ func (e AgentNetworkConsumptionDimensionKind) Valid() bool {
}
}
// Defines values for AgentNetworkManagedProxyState.
const (
AgentNetworkManagedProxyStateFailed AgentNetworkManagedProxyState = "failed"
AgentNetworkManagedProxyStateProvisioning AgentNetworkManagedProxyState = "provisioning"
AgentNetworkManagedProxyStateReady AgentNetworkManagedProxyState = "ready"
)
// Valid indicates whether the value is a known member of the AgentNetworkManagedProxyState enum.
func (e AgentNetworkManagedProxyState) Valid() bool {
switch e {
case AgentNetworkManagedProxyStateFailed:
return true
case AgentNetworkManagedProxyStateProvisioning:
return true
case AgentNetworkManagedProxyStateReady:
return true
default:
return false
}
}
// Defines values for CreateAzureIntegrationRequestHost.
const (
CreateAzureIntegrationRequestHostMicrosoftCom CreateAzureIntegrationRequestHost = "microsoft.com"
@@ -2224,6 +2245,33 @@ type AgentNetworkGuardrailRequest struct {
Name string `json:"name"`
}
// AgentNetworkManagedProxy A NetBird-managed Agent Network gateway deployment.
type AgentNetworkManagedProxy struct {
// Endpoint The account's gateway hostname.
Endpoint string `json:"endpoint"`
// Id Managed proxy deployment ID.
Id string `json:"id"`
// Message Failure detail reported by the rollout. Only set when state is `failed`.
Message *string `json:"message,omitempty"`
// Region Region of the cluster hosting the deployment.
Region *string `json:"region,omitempty"`
// State Derived deployment state. `provisioning` until the gateway is rolled out and connected, `ready` while the gateway actively serves the endpoint, `failed` when the rollout reported a failure.
State AgentNetworkManagedProxyState `json:"state"`
}
// AgentNetworkManagedProxyState Derived deployment state. `provisioning` until the gateway is rolled out and connected, `ready` while the gateway actively serves the endpoint, `failed` when the rollout reported a failure.
type AgentNetworkManagedProxyState string
// AgentNetworkManagedProxyConflict Conflict body returned when the account already has an Agent Network endpoint that managed provisioning does not own, naming that endpoint.
type AgentNetworkManagedProxyConflict struct {
// Endpoint The Agent Network endpoint already assigned to the account.
Endpoint string `json:"endpoint"`
}
// AgentNetworkModelDiscoveryRequest defines model for AgentNetworkModelDiscoveryRequest.
type AgentNetworkModelDiscoveryRequest struct {
// ApiKey Credential to query the vendor with, for a provider that has not been saved yet. Mutually exclusive with provider_id.
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
if ! which realpath > /dev/null 2>&1
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
if ! which realpath > /dev/null 2>&1