mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-21 04:49:10 +02:00
[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
This commit is contained in:
@@ -286,6 +286,9 @@ func (h *handler) updateAccountRequestSettings(req api.PutApiAccountsAccountIdJS
|
|||||||
if req.Settings.MetricsPushEnabled != nil {
|
if req.Settings.MetricsPushEnabled != nil {
|
||||||
returnSettings.MetricsPushEnabled = *req.Settings.MetricsPushEnabled
|
returnSettings.MetricsPushEnabled = *req.Settings.MetricsPushEnabled
|
||||||
}
|
}
|
||||||
|
if req.Settings.AgentNetworkOnly != nil {
|
||||||
|
returnSettings.AgentNetworkOnly = *req.Settings.AgentNetworkOnly
|
||||||
|
}
|
||||||
|
|
||||||
return returnSettings, nil
|
return returnSettings, nil
|
||||||
}
|
}
|
||||||
@@ -417,6 +420,7 @@ func toAccountResponse(accountID string, settings *types.Settings, meta *types.A
|
|||||||
AutoUpdateAlways: &settings.AutoUpdateAlways,
|
AutoUpdateAlways: &settings.AutoUpdateAlways,
|
||||||
Ipv6EnabledGroups: &settings.IPv6EnabledGroups,
|
Ipv6EnabledGroups: &settings.IPv6EnabledGroups,
|
||||||
MetricsPushEnabled: &settings.MetricsPushEnabled,
|
MetricsPushEnabled: &settings.MetricsPushEnabled,
|
||||||
|
AgentNetworkOnly: &settings.AgentNetworkOnly,
|
||||||
EmbeddedIdpEnabled: &settings.EmbeddedIdpEnabled,
|
EmbeddedIdpEnabled: &settings.EmbeddedIdpEnabled,
|
||||||
LocalAuthDisabled: &settings.LocalAuthDisabled,
|
LocalAuthDisabled: &settings.LocalAuthDisabled,
|
||||||
LocalMfaEnabled: &settings.LocalMfaEnabled,
|
LocalMfaEnabled: &settings.LocalMfaEnabled,
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
AutoUpdateAlways: br(false),
|
AutoUpdateAlways: br(false),
|
||||||
AutoUpdateVersion: sr(""),
|
AutoUpdateVersion: sr(""),
|
||||||
MetricsPushEnabled: br(false),
|
MetricsPushEnabled: br(false),
|
||||||
|
AgentNetworkOnly: br(false),
|
||||||
EmbeddedIdpEnabled: br(false),
|
EmbeddedIdpEnabled: br(false),
|
||||||
LocalAuthDisabled: br(false),
|
LocalAuthDisabled: br(false),
|
||||||
LocalMfaEnabled: br(false),
|
LocalMfaEnabled: br(false),
|
||||||
@@ -158,6 +159,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
AutoUpdateAlways: br(false),
|
AutoUpdateAlways: br(false),
|
||||||
AutoUpdateVersion: sr(""),
|
AutoUpdateVersion: sr(""),
|
||||||
MetricsPushEnabled: br(false),
|
MetricsPushEnabled: br(false),
|
||||||
|
AgentNetworkOnly: br(false),
|
||||||
EmbeddedIdpEnabled: br(false),
|
EmbeddedIdpEnabled: br(false),
|
||||||
LocalAuthDisabled: br(false),
|
LocalAuthDisabled: br(false),
|
||||||
LocalMfaEnabled: br(false),
|
LocalMfaEnabled: br(false),
|
||||||
@@ -186,6 +188,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
AutoUpdateAlways: br(false),
|
AutoUpdateAlways: br(false),
|
||||||
AutoUpdateVersion: sr("latest"),
|
AutoUpdateVersion: sr("latest"),
|
||||||
MetricsPushEnabled: br(false),
|
MetricsPushEnabled: br(false),
|
||||||
|
AgentNetworkOnly: br(false),
|
||||||
EmbeddedIdpEnabled: br(false),
|
EmbeddedIdpEnabled: br(false),
|
||||||
LocalAuthDisabled: br(false),
|
LocalAuthDisabled: br(false),
|
||||||
LocalMfaEnabled: br(false),
|
LocalMfaEnabled: br(false),
|
||||||
@@ -214,6 +217,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
AutoUpdateAlways: br(false),
|
AutoUpdateAlways: br(false),
|
||||||
AutoUpdateVersion: sr(""),
|
AutoUpdateVersion: sr(""),
|
||||||
MetricsPushEnabled: br(false),
|
MetricsPushEnabled: br(false),
|
||||||
|
AgentNetworkOnly: br(false),
|
||||||
EmbeddedIdpEnabled: br(false),
|
EmbeddedIdpEnabled: br(false),
|
||||||
LocalAuthDisabled: br(false),
|
LocalAuthDisabled: br(false),
|
||||||
LocalMfaEnabled: br(false),
|
LocalMfaEnabled: br(false),
|
||||||
@@ -242,6 +246,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
AutoUpdateAlways: br(false),
|
AutoUpdateAlways: br(false),
|
||||||
AutoUpdateVersion: sr(""),
|
AutoUpdateVersion: sr(""),
|
||||||
MetricsPushEnabled: br(false),
|
MetricsPushEnabled: br(false),
|
||||||
|
AgentNetworkOnly: br(false),
|
||||||
EmbeddedIdpEnabled: br(false),
|
EmbeddedIdpEnabled: br(false),
|
||||||
LocalAuthDisabled: br(false),
|
LocalAuthDisabled: br(false),
|
||||||
LocalMfaEnabled: br(false),
|
LocalMfaEnabled: br(false),
|
||||||
@@ -270,6 +275,65 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
AutoUpdateAlways: br(false),
|
AutoUpdateAlways: br(false),
|
||||||
AutoUpdateVersion: sr(""),
|
AutoUpdateVersion: sr(""),
|
||||||
MetricsPushEnabled: br(false),
|
MetricsPushEnabled: br(false),
|
||||||
|
AgentNetworkOnly: br(false),
|
||||||
|
EmbeddedIdpEnabled: br(false),
|
||||||
|
LocalAuthDisabled: br(false),
|
||||||
|
LocalMfaEnabled: br(false),
|
||||||
|
},
|
||||||
|
expectedArray: false,
|
||||||
|
expectedID: accountID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PutAccount OK enabling agent_network_only",
|
||||||
|
expectedBody: true,
|
||||||
|
requestType: http.MethodPut,
|
||||||
|
requestPath: "/api/accounts/" + accountID,
|
||||||
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true,\"agent_network_only\": true},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectedSettings: api.AccountSettings{
|
||||||
|
PeerLoginExpiration: 15552000,
|
||||||
|
PeerLoginExpirationEnabled: true,
|
||||||
|
GroupsPropagationEnabled: br(false),
|
||||||
|
JwtGroupsClaimName: sr(""),
|
||||||
|
JwtGroupsEnabled: br(false),
|
||||||
|
JwtAllowGroups: &[]string{},
|
||||||
|
RegularUsersViewBlocked: false,
|
||||||
|
RoutingPeerDnsResolutionEnabled: br(false),
|
||||||
|
LazyConnectionEnabled: br(false),
|
||||||
|
DnsDomain: sr(""),
|
||||||
|
AutoUpdateAlways: br(false),
|
||||||
|
AutoUpdateVersion: sr(""),
|
||||||
|
MetricsPushEnabled: br(false),
|
||||||
|
AgentNetworkOnly: br(true),
|
||||||
|
EmbeddedIdpEnabled: br(false),
|
||||||
|
LocalAuthDisabled: br(false),
|
||||||
|
LocalMfaEnabled: br(false),
|
||||||
|
},
|
||||||
|
expectedArray: false,
|
||||||
|
expectedID: accountID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PutAccount OK disabling agent_network_only again",
|
||||||
|
expectedBody: true,
|
||||||
|
requestType: http.MethodPut,
|
||||||
|
requestPath: "/api/accounts/" + accountID,
|
||||||
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true,\"agent_network_only\": false},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectedSettings: api.AccountSettings{
|
||||||
|
PeerLoginExpiration: 15552000,
|
||||||
|
PeerLoginExpirationEnabled: true,
|
||||||
|
GroupsPropagationEnabled: br(false),
|
||||||
|
JwtGroupsClaimName: sr(""),
|
||||||
|
JwtGroupsEnabled: br(false),
|
||||||
|
JwtAllowGroups: &[]string{},
|
||||||
|
RegularUsersViewBlocked: false,
|
||||||
|
RoutingPeerDnsResolutionEnabled: br(false),
|
||||||
|
LazyConnectionEnabled: br(false),
|
||||||
|
DnsDomain: sr(""),
|
||||||
|
AutoUpdateAlways: br(false),
|
||||||
|
AutoUpdateVersion: sr(""),
|
||||||
|
MetricsPushEnabled: br(false),
|
||||||
|
AgentNetworkOnly: br(false),
|
||||||
EmbeddedIdpEnabled: br(false),
|
EmbeddedIdpEnabled: br(false),
|
||||||
LocalAuthDisabled: br(false),
|
LocalAuthDisabled: br(false),
|
||||||
LocalMfaEnabled: br(false),
|
LocalMfaEnabled: br(false),
|
||||||
|
|||||||
@@ -1605,7 +1605,7 @@ func (s *SqlStore) getAccount(ctx context.Context, accountID string) (*types.Acc
|
|||||||
settings_jwt_groups_enabled, settings_jwt_groups_claim_name, settings_jwt_allow_groups,
|
settings_jwt_groups_enabled, settings_jwt_groups_claim_name, settings_jwt_allow_groups,
|
||||||
settings_routing_peer_dns_resolution_enabled, settings_dns_domain, settings_network_range,
|
settings_routing_peer_dns_resolution_enabled, settings_dns_domain, settings_network_range,
|
||||||
settings_network_range_v6, settings_ipv6_enabled_groups, settings_lazy_connection_enabled,
|
settings_network_range_v6, settings_ipv6_enabled_groups, settings_lazy_connection_enabled,
|
||||||
settings_local_mfa_enabled, settings_metrics_push_enabled,
|
settings_local_mfa_enabled, settings_metrics_push_enabled, settings_agent_network_only,
|
||||||
-- Embedded ExtraSettings
|
-- Embedded ExtraSettings
|
||||||
settings_extra_peer_approval_enabled, settings_extra_user_approval_required,
|
settings_extra_peer_approval_enabled, settings_extra_user_approval_required,
|
||||||
settings_extra_integrated_validator, settings_extra_integrated_validator_groups
|
settings_extra_integrated_validator, settings_extra_integrated_validator_groups
|
||||||
@@ -1629,6 +1629,7 @@ func (s *SqlStore) getAccount(ctx context.Context, accountID string) (*types.Acc
|
|||||||
sLazyConnectionEnabled sql.NullBool
|
sLazyConnectionEnabled sql.NullBool
|
||||||
sLocalMFAEnabled sql.NullBool
|
sLocalMFAEnabled sql.NullBool
|
||||||
sMetricsPushEnabled sql.NullBool
|
sMetricsPushEnabled sql.NullBool
|
||||||
|
sAgentNetworkOnly sql.NullBool
|
||||||
sExtraPeerApprovalEnabled sql.NullBool
|
sExtraPeerApprovalEnabled sql.NullBool
|
||||||
sExtraUserApprovalRequired sql.NullBool
|
sExtraUserApprovalRequired sql.NullBool
|
||||||
sExtraIntegratedValidator sql.NullString
|
sExtraIntegratedValidator sql.NullString
|
||||||
@@ -1651,7 +1652,7 @@ func (s *SqlStore) getAccount(ctx context.Context, accountID string) (*types.Acc
|
|||||||
&sJWTGroupsEnabled, &sJWTGroupsClaimName, &sJWTAllowGroups,
|
&sJWTGroupsEnabled, &sJWTGroupsClaimName, &sJWTAllowGroups,
|
||||||
&sRoutingPeerDNSResolutionEnabled, &sDNSDomain, &sNetworkRange,
|
&sRoutingPeerDNSResolutionEnabled, &sDNSDomain, &sNetworkRange,
|
||||||
&sNetworkRangeV6, &sIPv6EnabledGroups, &sLazyConnectionEnabled,
|
&sNetworkRangeV6, &sIPv6EnabledGroups, &sLazyConnectionEnabled,
|
||||||
&sLocalMFAEnabled, &sMetricsPushEnabled,
|
&sLocalMFAEnabled, &sMetricsPushEnabled, &sAgentNetworkOnly,
|
||||||
&sExtraPeerApprovalEnabled, &sExtraUserApprovalRequired,
|
&sExtraPeerApprovalEnabled, &sExtraUserApprovalRequired,
|
||||||
&sExtraIntegratedValidator, &sExtraIntegratedValidatorGroups,
|
&sExtraIntegratedValidator, &sExtraIntegratedValidatorGroups,
|
||||||
)
|
)
|
||||||
@@ -1720,6 +1721,9 @@ func (s *SqlStore) getAccount(ctx context.Context, accountID string) (*types.Acc
|
|||||||
if sMetricsPushEnabled.Valid {
|
if sMetricsPushEnabled.Valid {
|
||||||
account.Settings.MetricsPushEnabled = sMetricsPushEnabled.Bool
|
account.Settings.MetricsPushEnabled = sMetricsPushEnabled.Bool
|
||||||
}
|
}
|
||||||
|
if sAgentNetworkOnly.Valid {
|
||||||
|
account.Settings.AgentNetworkOnly = sAgentNetworkOnly.Bool
|
||||||
|
}
|
||||||
if sJWTAllowGroups.Valid {
|
if sJWTAllowGroups.Valid {
|
||||||
_ = json.Unmarshal([]byte(sJWTAllowGroups.String), &account.Settings.JWTAllowGroups)
|
_ = json.Unmarshal([]byte(sJWTAllowGroups.String), &account.Settings.JWTAllowGroups)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1245,6 +1245,31 @@ func TestSqlite_CreateAndGetObjectInTransaction(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSqlStore_SaveAccountPersistsAgentNetworkOnly(t *testing.T) {
|
||||||
|
store, cleanup, err := NewTestStoreFromSQL(context.Background(), "../testdata/store.sql", t.TempDir())
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
|
account, err := store.GetAccount(context.Background(), accountID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, account.Settings.AgentNetworkOnly, "setting should default to false")
|
||||||
|
|
||||||
|
account.Settings.AgentNetworkOnly = true
|
||||||
|
require.NoError(t, store.SaveAccount(context.Background(), account))
|
||||||
|
|
||||||
|
reloaded, err := store.GetAccount(context.Background(), accountID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, reloaded.Settings.AgentNetworkOnly, "setting should survive a save/load round-trip")
|
||||||
|
|
||||||
|
reloaded.Settings.AgentNetworkOnly = false
|
||||||
|
require.NoError(t, store.SaveAccount(context.Background(), reloaded))
|
||||||
|
|
||||||
|
disabled, err := store.GetAccount(context.Background(), accountID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, disabled.Settings.AgentNetworkOnly, "disabling should persist")
|
||||||
|
}
|
||||||
|
|
||||||
func TestSqlStore_GetAccountUsers(t *testing.T) {
|
func TestSqlStore_GetAccountUsers(t *testing.T) {
|
||||||
store, cleanup, err := NewTestStoreFromSQL(context.Background(), "../testdata/extended-store.sql", t.TempDir())
|
store, cleanup, err := NewTestStoreFromSQL(context.Background(), "../testdata/extended-store.sql", t.TempDir())
|
||||||
t.Cleanup(cleanup)
|
t.Cleanup(cleanup)
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ type Settings struct {
|
|||||||
// MetricsPushEnabled globally enables or disables client metrics push for the account
|
// MetricsPushEnabled globally enables or disables client metrics push for the account
|
||||||
MetricsPushEnabled bool `gorm:"default:false"`
|
MetricsPushEnabled bool `gorm:"default:false"`
|
||||||
|
|
||||||
|
// AgentNetworkOnly limits the dashboard to the Agent Network surface for this account.
|
||||||
|
// Set for accounts created via netbird.ai signups; users can disable it later.
|
||||||
|
AgentNetworkOnly bool `gorm:"default:false"`
|
||||||
|
|
||||||
// EmbeddedIdpEnabled indicates if the embedded identity provider is enabled.
|
// EmbeddedIdpEnabled indicates if the embedded identity provider is enabled.
|
||||||
// This is a runtime-only field, not stored in the database.
|
// This is a runtime-only field, not stored in the database.
|
||||||
EmbeddedIdpEnabled bool `gorm:"-"`
|
EmbeddedIdpEnabled bool `gorm:"-"`
|
||||||
@@ -114,6 +118,7 @@ func (s *Settings) Copy() *Settings {
|
|||||||
AutoUpdateAlways: s.AutoUpdateAlways,
|
AutoUpdateAlways: s.AutoUpdateAlways,
|
||||||
IPv6EnabledGroups: slices.Clone(s.IPv6EnabledGroups),
|
IPv6EnabledGroups: slices.Clone(s.IPv6EnabledGroups),
|
||||||
MetricsPushEnabled: s.MetricsPushEnabled,
|
MetricsPushEnabled: s.MetricsPushEnabled,
|
||||||
|
AgentNetworkOnly: s.AgentNetworkOnly,
|
||||||
EmbeddedIdpEnabled: s.EmbeddedIdpEnabled,
|
EmbeddedIdpEnabled: s.EmbeddedIdpEnabled,
|
||||||
LocalAuthDisabled: s.LocalAuthDisabled,
|
LocalAuthDisabled: s.LocalAuthDisabled,
|
||||||
LocalMfaEnabled: s.LocalMfaEnabled,
|
LocalMfaEnabled: s.LocalMfaEnabled,
|
||||||
|
|||||||
@@ -375,6 +375,10 @@ components:
|
|||||||
description: Enables or disables client metrics push for all peers in the account
|
description: Enables or disables client metrics push for all peers in the account
|
||||||
type: boolean
|
type: boolean
|
||||||
example: false
|
example: false
|
||||||
|
agent_network_only:
|
||||||
|
description: Limits the dashboard to the Agent Network surface for this account. Set for accounts created via netbird.ai signups and can be disabled later.
|
||||||
|
type: boolean
|
||||||
|
example: false
|
||||||
embedded_idp_enabled:
|
embedded_idp_enabled:
|
||||||
description: Indicates whether the embedded identity provider (Dex) is enabled for this account. This is a read-only field.
|
description: Indicates whether the embedded identity provider (Dex) is enabled for this account. This is a read-only field.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|||||||
@@ -1647,6 +1647,9 @@ type AccountRequest struct {
|
|||||||
|
|
||||||
// AccountSettings defines model for AccountSettings.
|
// AccountSettings defines model for AccountSettings.
|
||||||
type AccountSettings struct {
|
type AccountSettings struct {
|
||||||
|
// AgentNetworkOnly Limits the dashboard to the Agent Network surface for this account. Set for accounts created via netbird.ai signups and can be disabled later.
|
||||||
|
AgentNetworkOnly *bool `json:"agent_network_only,omitempty"`
|
||||||
|
|
||||||
// AutoUpdateAlways When true, updates are installed automatically in the background. When false, updates require user interaction from the UI.
|
// AutoUpdateAlways When true, updates are installed automatically in the background. When false, updates require user interaction from the UI.
|
||||||
AutoUpdateAlways *bool `json:"auto_update_always,omitempty"`
|
AutoUpdateAlways *bool `json:"auto_update_always,omitempty"`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user