mirror of
https://github.com/mattermost/mattermost.git
synced 2026-08-26 21:27:40 -05:00
[MM-69528] Enable feature flags for ranked attributes, permission policies and masking by default (#37265)
* [MM-69528] Enable feature flags for ranked attributes, permission policies and masking Change the default value to true for AttributeValueMasking, PermissionPolicies, ChannelPermissionPolicies, PolicySimulation and PropertyFieldRank, and update the unit tests and a stale comment that pinned the old defaults. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Fix access control tests for feature flags enabled by default Tests that assumed AttributeValueMasking, PermissionPolicies, and PolicySimulation were off by default now explicitly disable those flags in setup or use SetReadOnlyFF(false) before runtime UpdateConfig calls. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Add regression test for PropertyFieldRank default Co-authored-by: mattermost-code <matty-code@mattermost.com> * Disable masking in store-mock tests that assume flag off Co-authored-by: mattermost-code <matty-code@mattermost.com> * Fix store-mock masking helper without UpdateConfig UpdateConfig triggers config persistence listeners that call Store.Post() on the mock store. Mutate feature flags in place instead. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Fix masking-off deactivation test for new flag default Co-authored-by: mattermost-code <matty-code@mattermost.com> * Fix Setup/InitBasic compile errors in access control tests Pass testing.TB to Setup and InitBasic after removing redundant feature-flag SetupConfig wrappers. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Restore ABAC feature-flag defaults in test cleanup Defer blocks in access_control_test.go were resetting PermissionPolicies, ChannelPermissionPolicies, and PolicySimulation to false after subtests, leaving the shared TestHelper in a partially-disabled state. With these flags now defaulting to true, cleanup should restore the default-enabled baseline instead. Co-authored-by: mattermost-code <matty-code@mattermost.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com>
This commit is contained in:
co-authored by
mattermost-code
Cursor Agent
parent
98a9c89514
commit
939afca46f
@@ -16,8 +16,32 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// maskingOffTestConfig disables attribute-value masking for policy-endpoint
|
||||
// tests that do not cover masking. ABAC and other ABAC sub-flags default on.
|
||||
func maskingOffTestConfig(cfg *model.Config) {
|
||||
cfg.FeatureFlags.AttributeValueMasking = false
|
||||
}
|
||||
|
||||
func allowTestFeatureFlagUpdates(t *testing.T, th *TestHelper) {
|
||||
t.Helper()
|
||||
th.ConfigStore.SetReadOnlyFF(false)
|
||||
}
|
||||
|
||||
func updateTestFeatureFlags(t *testing.T, th *TestHelper, fn func(cfg *model.Config)) {
|
||||
t.Helper()
|
||||
allowTestFeatureFlagUpdates(t, th)
|
||||
th.App.UpdateConfig(fn)
|
||||
}
|
||||
|
||||
func restoreABACFeatureFlagDefaults(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.FeatureFlags.ChannelPermissionPolicies = true
|
||||
cfg.FeatureFlags.PolicySimulation = true
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = model.NewPointer(true)
|
||||
}
|
||||
|
||||
func TestCreateAccessControlPolicy(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
samplePolicy := &model.AccessControlPolicy{
|
||||
ID: th.BasicChannel.Id,
|
||||
@@ -273,7 +297,7 @@ func TestCreateAccessControlPolicy(t *testing.T) {
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok, "SetLicense should return true")
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(true)
|
||||
})
|
||||
@@ -319,7 +343,7 @@ func TestCreateAccessControlPolicy(t *testing.T) {
|
||||
th.App.Srv().Channels().AccessControl = mockAccessControlService
|
||||
mockAccessControlService.On("SavePolicy", mock.AnythingOfType("*request.Context"), mock.AnythingOfType("*model.AccessControlPolicy")).Return(permissionPolicy, nil).Times(1)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(true)
|
||||
})
|
||||
@@ -341,14 +365,12 @@ func TestCreateAccessControlPolicy(t *testing.T) {
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok, "SetLicense should return true")
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.FeatureFlags.ChannelPermissionPolicies = false
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(true)
|
||||
})
|
||||
defer th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
})
|
||||
defer updateTestFeatureFlags(t, th, restoreABACFeatureFlagDefaults)
|
||||
|
||||
channelPolicy := &model.AccessControlPolicy{
|
||||
ID: model.NewId(),
|
||||
@@ -381,14 +403,12 @@ func TestCreateAccessControlPolicy(t *testing.T) {
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok, "SetLicense should return true")
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
cfg.FeatureFlags.ChannelPermissionPolicies = true
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(true)
|
||||
})
|
||||
defer th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.ChannelPermissionPolicies = false
|
||||
})
|
||||
defer updateTestFeatureFlags(t, th, restoreABACFeatureFlagDefaults)
|
||||
|
||||
channelPolicy := &model.AccessControlPolicy{
|
||||
ID: model.NewId(),
|
||||
@@ -443,15 +463,12 @@ func TestCreateAccessControlPolicy(t *testing.T) {
|
||||
// other tests, so the mock returns success straight away.
|
||||
mockAccessControlService.On("SavePolicy", mock.AnythingOfType("*request.Context"), mock.AnythingOfType("*model.AccessControlPolicy")).Return(channelPolicy, nil).Times(1)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.FeatureFlags.ChannelPermissionPolicies = true
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(true)
|
||||
})
|
||||
defer th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
cfg.FeatureFlags.ChannelPermissionPolicies = false
|
||||
})
|
||||
defer updateTestFeatureFlags(t, th, restoreABACFeatureFlagDefaults)
|
||||
|
||||
_, resp, err := th.SystemAdminClient.CreateAccessControlPolicy(context.Background(), channelPolicy)
|
||||
require.NoError(t, err)
|
||||
@@ -498,7 +515,7 @@ func TestCreateAccessControlPolicy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAccessControlPolicy(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
samplePolicy := &model.AccessControlPolicy{
|
||||
ID: model.NewId(),
|
||||
@@ -626,7 +643,7 @@ func TestGetAccessControlPolicy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDeleteAccessControlPolicy(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
samplePolicyID := model.NewId()
|
||||
|
||||
@@ -702,7 +719,7 @@ func TestDeleteAccessControlPolicy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckExpression(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
t.Run("CheckExpression without license", func(t *testing.T) {
|
||||
_, resp, err := th.SystemAdminClient.CheckExpression(context.Background(), "true")
|
||||
@@ -837,7 +854,7 @@ func TestCheckExpression(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTestExpression(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
t.Run("TestExpression without license", func(t *testing.T) {
|
||||
_, resp, err := th.SystemAdminClient.TestExpression(context.Background(), model.QueryExpressionParams{})
|
||||
@@ -884,7 +901,7 @@ func TestTestExpression(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearchAccessControlPolicies(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
t.Run("SearchAccessControlPolicies without license", func(t *testing.T) {
|
||||
_, resp, err := th.SystemAdminClient.SearchAccessControlPolicies(context.Background(), model.AccessControlPolicySearch{})
|
||||
@@ -935,7 +952,7 @@ func TestSearchAccessControlPolicies(t *testing.T) {
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok, "SetLicense should return true")
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(true)
|
||||
})
|
||||
@@ -959,7 +976,7 @@ func TestSearchAccessControlPolicies(t *testing.T) {
|
||||
Type: model.AccessControlPolicyTypePermission,
|
||||
}).Return([]*model.AccessControlPolicy{}, int64(0), nil).Times(1)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(true)
|
||||
})
|
||||
@@ -1058,7 +1075,7 @@ func TestSearchTeamAccessControlPolicies(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAssignAccessPolicy(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
samplePolicy := &model.AccessControlPolicy{
|
||||
ID: model.NewId(),
|
||||
@@ -1135,7 +1152,7 @@ func TestAssignAccessPolicy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnassignAccessPolicy(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
samplePolicy := &model.AccessControlPolicy{
|
||||
ID: model.NewId(),
|
||||
@@ -1208,7 +1225,7 @@ func TestUnassignAccessPolicy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetChannelsForAccessControlPolicy(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
samplePolicy := &model.AccessControlPolicy{
|
||||
ID: model.NewId(),
|
||||
@@ -1266,7 +1283,7 @@ func TestGetChannelsForAccessControlPolicy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSearchChannelsForAccessControlPolicy(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
newSamplePolicy := func() *model.AccessControlPolicy {
|
||||
return &model.AccessControlPolicy{
|
||||
@@ -1480,7 +1497,7 @@ func TestSearchChannelsForAccessControlPolicy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetActiveStatus(t *testing.T) {
|
||||
th := Setup(t).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
samplePolicy := &model.AccessControlPolicy{
|
||||
ID: th.BasicChannel.Id,
|
||||
@@ -1669,8 +1686,9 @@ func setupTeamAdminABAC(t *testing.T, th *TestHelper) *mocks.AccessControlServic
|
||||
mockACS := &mocks.AccessControlServiceInterface{}
|
||||
th.App.Srv().Channels().AccessControl = mockACS
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(true)
|
||||
cfg.FeatureFlags.AttributeValueMasking = false
|
||||
})
|
||||
|
||||
th.AddPermissionToRole(t, model.PermissionManageTeamAccessRules.Id, model.TeamAdminRoleId)
|
||||
@@ -1713,12 +1731,7 @@ func newParentPolicy(teamID string) *model.AccessControlPolicy {
|
||||
// fail-closed branch (unknown property field) so the masking always produces the
|
||||
// "--------" sentinel without requiring a real CPA setup.
|
||||
func TestResponseMaskingOnPolicyEndpoints(t *testing.T) {
|
||||
// SetupConfig sets FFs before route init via SetReadOnlyFF(false). Avoids
|
||||
// os.Setenv which isn't parallel-safe.
|
||||
th := SetupConfig(t, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.AttributeBasedAccessControl = true
|
||||
cfg.FeatureFlags.AttributeValueMasking = true
|
||||
}).InitBasic(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok, "SetLicense should return true")
|
||||
@@ -2652,7 +2665,7 @@ func TestScopeReconciliationCrossTeam(t *testing.T) {
|
||||
// proxies to the access-control service which we mock here so the test
|
||||
// stays focused on the API surface (auth + payload validation).
|
||||
func TestSimulatePolicyForUsers(t *testing.T) {
|
||||
th := SetupConfig(t, func(cfg *model.Config) { cfg.FeatureFlags.AttributeBasedAccessControl = true }).InitBasic(t)
|
||||
th := SetupConfig(t, maskingOffTestConfig).InitBasic(t)
|
||||
|
||||
t.Run("returns 501 when umbrella PermissionPolicies flag is disabled", func(t *testing.T) {
|
||||
// Set the Enterprise Advanced license up-front so any future
|
||||
@@ -2667,7 +2680,7 @@ func TestSimulatePolicyForUsers(t *testing.T) {
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
cfg.FeatureFlags.PolicySimulation = true // sub-flag alone must not be enough
|
||||
})
|
||||
@@ -2695,13 +2708,11 @@ func TestSimulatePolicyForUsers(t *testing.T) {
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.FeatureFlags.PolicySimulation = false
|
||||
})
|
||||
defer th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
})
|
||||
defer updateTestFeatureFlags(t, th, restoreABACFeatureFlagDefaults)
|
||||
|
||||
body := mustMarshal(t, model.PolicySimulationByUsersParams{
|
||||
Policy: &model.AccessControlPolicy{ID: model.NewId(), Type: model.AccessControlPolicyTypeChannel},
|
||||
@@ -2723,14 +2734,11 @@ func TestSimulatePolicyForUsers(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
defer th.App.Srv().SetLicense(nil)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.FeatureFlags.PolicySimulation = true
|
||||
})
|
||||
defer th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
cfg.FeatureFlags.PolicySimulation = false
|
||||
})
|
||||
defer updateTestFeatureFlags(t, th, restoreABACFeatureFlagDefaults)
|
||||
|
||||
body := mustMarshal(t, model.PolicySimulationByUsersParams{
|
||||
Policy: &model.AccessControlPolicy{ID: model.NewId(), Type: model.AccessControlPolicyTypeChannel},
|
||||
@@ -2747,15 +2755,12 @@ func TestSimulatePolicyForUsers(t *testing.T) {
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.FeatureFlags.PolicySimulation = true
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = model.NewPointer(true)
|
||||
})
|
||||
defer th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
cfg.FeatureFlags.PolicySimulation = false
|
||||
})
|
||||
defer updateTestFeatureFlags(t, th, restoreABACFeatureFlagDefaults)
|
||||
|
||||
mockACS := &mocks.AccessControlServiceInterface{}
|
||||
th.App.Srv().Channels().AccessControl = mockACS
|
||||
@@ -2774,15 +2779,12 @@ func TestSimulatePolicyForUsers(t *testing.T) {
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.FeatureFlags.PolicySimulation = true
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = model.NewPointer(true)
|
||||
})
|
||||
defer th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
cfg.FeatureFlags.PolicySimulation = false
|
||||
})
|
||||
defer updateTestFeatureFlags(t, th, restoreABACFeatureFlagDefaults)
|
||||
|
||||
mockACS := &mocks.AccessControlServiceInterface{}
|
||||
mockACS.On("SimulatePolicyForUsers", mock.Anything, mock.Anything).Return(
|
||||
@@ -2807,15 +2809,12 @@ func TestSimulatePolicyForUsers(t *testing.T) {
|
||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||
require.True(t, ok)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
updateTestFeatureFlags(t, th, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
cfg.FeatureFlags.PolicySimulation = true
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = model.NewPointer(true)
|
||||
})
|
||||
defer th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
cfg.FeatureFlags.PolicySimulation = false
|
||||
})
|
||||
defer updateTestFeatureFlags(t, th, restoreABACFeatureFlagDefaults)
|
||||
|
||||
mockACS := &mocks.AccessControlServiceInterface{}
|
||||
th.App.Srv().Channels().AccessControl = mockACS
|
||||
|
||||
@@ -25,8 +25,19 @@ func celSafeName() string {
|
||||
return "f_" + model.NewId()
|
||||
}
|
||||
|
||||
func storeMockWithMaskingOff(tb testing.TB) *TestHelper {
|
||||
tb.Helper()
|
||||
th := SetupWithStoreMock(tb)
|
||||
// Mutate in place — UpdateConfig persists config and triggers
|
||||
// listeners that call Store.Post(), which the mock store lacks.
|
||||
th.App.Config().FeatureFlags.AttributeValueMasking = false
|
||||
return th
|
||||
}
|
||||
|
||||
func TestCreateOrUpdateAccessControlPolicy(t *testing.T) {
|
||||
th := Setup(t).InitBasic(t)
|
||||
th := SetupConfig(t, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.AttributeValueMasking = false
|
||||
}).InitBasic(t)
|
||||
|
||||
t.Run("Feature not enabled", func(t *testing.T) {
|
||||
th.App.Srv().ch.AccessControl = nil
|
||||
@@ -115,7 +126,7 @@ func TestCreateOrUpdateAccessControlPolicy(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Channel-type policy broadcasts policy enforced update", func(t *testing.T) {
|
||||
thMock := SetupWithStoreMock(t)
|
||||
thMock := storeMockWithMaskingOff(t)
|
||||
|
||||
channelID := model.NewId()
|
||||
channelPolicy := &model.AccessControlPolicy{
|
||||
@@ -157,7 +168,7 @@ func TestCreateOrUpdateAccessControlPolicy(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Parent-type policy does not broadcast channel-only update", func(t *testing.T) {
|
||||
thMock := SetupWithStoreMock(t)
|
||||
thMock := storeMockWithMaskingOff(t)
|
||||
|
||||
parentID := model.NewId()
|
||||
parentPolicy := &model.AccessControlPolicy{
|
||||
@@ -341,10 +352,7 @@ func TestDeleteAccessControlPolicy(t *testing.T) {
|
||||
// could not audit. The canonical walker's HasMaskedValuesForCaller is mocked
|
||||
// to return true, simulating a hidden-value field without requiring a full
|
||||
// CPA setup for the test.
|
||||
th := SetupConfig(t, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.AttributeBasedAccessControl = true
|
||||
cfg.FeatureFlags.AttributeValueMasking = true
|
||||
}).InitBasic(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
callerID := model.NewId()
|
||||
th.Context = th.Context.WithSession(&model.Session{UserId: callerID, Id: model.NewId()}).(*request.Context)
|
||||
@@ -378,9 +386,7 @@ func TestDeleteAccessControlPolicy(t *testing.T) {
|
||||
// Belt-and-braces: with AttributeValueMasking off, the masking guard must not
|
||||
// fire — the policy deletes normally even if the caller wouldn't have seen all
|
||||
// values. Guards against accidentally inverting the flag condition.
|
||||
thMock := SetupWithStoreMock(t)
|
||||
// Note: SetupWithStoreMock doesn't take a config callback. Feature flags
|
||||
// default to false, which is exactly the state this test wants.
|
||||
thMock := storeMockWithMaskingOff(t)
|
||||
|
||||
thMock.Context = thMock.Context.WithSession(&model.Session{UserId: model.NewId(), Id: model.NewId()}).(*request.Context)
|
||||
|
||||
@@ -2149,6 +2155,7 @@ func TestHasPermissionToFileAction(t *testing.T) {
|
||||
mockAccessControl := &mocks.AccessControlServiceInterface{}
|
||||
th.App.Srv().ch.AccessControl = mockAccessControl
|
||||
|
||||
th.ConfigStore.SetReadOnlyFF(false)
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(false)
|
||||
cfg.FeatureFlags.PermissionPolicies = true
|
||||
@@ -2162,6 +2169,7 @@ func TestHasPermissionToFileAction(t *testing.T) {
|
||||
mockAccessControl := &mocks.AccessControlServiceInterface{}
|
||||
th.App.Srv().ch.AccessControl = mockAccessControl
|
||||
|
||||
th.ConfigStore.SetReadOnlyFF(false)
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.AccessControlSettings.EnableAttributeBasedAccessControl = new(true)
|
||||
cfg.FeatureFlags.PermissionPolicies = false
|
||||
@@ -4535,7 +4543,7 @@ func TestPublishChannelPolicyEnforcedUpdateHydratesBroadcastPayload(t *testing.T
|
||||
// broadcast payload so connected clients can react to action-set
|
||||
// changes without a follow-up REST round-trip. The hydration happens
|
||||
// after GetChannel reloads the (now-policy-enforced) channel post-save.
|
||||
thMock := SetupWithStoreMock(t)
|
||||
thMock := storeMockWithMaskingOff(t)
|
||||
|
||||
channelID := model.NewId()
|
||||
channelPolicy := &model.AccessControlPolicy{
|
||||
@@ -4980,10 +4988,7 @@ func TestUpdateAccessControlPoliciesActive_MaskingGuard(t *testing.T) {
|
||||
t.Run("deactivation blocked when caller has masked values", func(t *testing.T) {
|
||||
// policyHasMaskedValuesForCaller resolves the property group from the store,
|
||||
// so this subtest uses SetupConfig + InitBasic rather than a mock store.
|
||||
th := SetupConfig(t, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.AttributeBasedAccessControl = true
|
||||
cfg.FeatureFlags.AttributeValueMasking = true
|
||||
}).InitBasic(t)
|
||||
th := Setup(t).InitBasic(t)
|
||||
|
||||
callerID := model.NewId()
|
||||
th.Context = th.Context.WithSession(&model.Session{UserId: callerID, Id: model.NewId()}).(*request.Context)
|
||||
@@ -5016,10 +5021,6 @@ func TestUpdateAccessControlPoliciesActive_MaskingGuard(t *testing.T) {
|
||||
t.Run("activation always allowed even when caller has masked values", func(t *testing.T) {
|
||||
// The guard skips Active=true updates, so no property store access is needed.
|
||||
thMock := SetupWithStoreMock(t)
|
||||
thMock.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.AttributeBasedAccessControl = true
|
||||
cfg.FeatureFlags.AttributeValueMasking = true
|
||||
})
|
||||
|
||||
callerID := model.NewId()
|
||||
thMock.Context = thMock.Context.WithSession(&model.Session{UserId: callerID, Id: model.NewId()}).(*request.Context)
|
||||
@@ -5057,7 +5058,7 @@ func TestUpdateAccessControlPoliciesActive_MaskingGuard(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("deactivation allowed when masking flag is off", func(t *testing.T) {
|
||||
thMock := SetupWithStoreMock(t)
|
||||
thMock := storeMockWithMaskingOff(t)
|
||||
thMock.Context = thMock.Context.WithSession(&model.Session{UserId: model.NewId(), Id: model.NewId()}).(*request.Context)
|
||||
|
||||
channelID := model.NewId()
|
||||
@@ -5190,10 +5191,7 @@ func TestMaskPolicyExpressions_FailClosedUsesDenyAllSentinel(t *testing.T) {
|
||||
callerID := model.NewId()
|
||||
|
||||
t.Run("MaskExpressionForCaller failure masks rule to deny-all sentinel", func(t *testing.T) {
|
||||
th2 := SetupConfig(t, func(cfg *model.Config) {
|
||||
cfg.FeatureFlags.AttributeBasedAccessControl = true
|
||||
cfg.FeatureFlags.AttributeValueMasking = true
|
||||
}).InitBasic(t)
|
||||
th2 := Setup(t).InitBasic(t)
|
||||
|
||||
policy := &model.AccessControlPolicy{
|
||||
Rules: []model.AccessControlPolicyRule{
|
||||
|
||||
@@ -76,7 +76,7 @@ func (a *App) publishPropertyFieldEvent(rctx request.CTX, eventType model.Websoc
|
||||
// (template/system/channel in the access_control group) legitimately use the
|
||||
// rank type and ship behind the separate, GA-by-default ClassificationMarkings
|
||||
// flag. Gating those here would break the classification admin panel (create
|
||||
// and edit alike) whenever PropertyFieldRank is off, which is the default.
|
||||
// and edit alike) whenever PropertyFieldRank is off.
|
||||
func (a *App) rankPropertyFieldGate(where string, field *model.PropertyField) *model.AppError {
|
||||
if field == nil || field.Type != model.PropertyFieldTypeRank {
|
||||
return nil
|
||||
|
||||
@@ -178,11 +178,11 @@ func (f *FeatureFlags) SetDefaults() {
|
||||
f.ExperimentalAuditSettingsSystemConsoleUI = true
|
||||
f.CustomProfileAttributes = true
|
||||
f.AttributeBasedAccessControl = true
|
||||
f.AttributeValueMasking = false
|
||||
f.PermissionPolicies = false
|
||||
f.AttributeValueMasking = true
|
||||
f.PermissionPolicies = true
|
||||
f.TeamMembershipAccessControl = false
|
||||
f.ChannelPermissionPolicies = false
|
||||
f.PolicySimulation = false
|
||||
f.ChannelPermissionPolicies = true
|
||||
f.PolicySimulation = true
|
||||
f.ContentFlagging = true
|
||||
f.EnableMattermostEntry = true
|
||||
|
||||
@@ -215,7 +215,7 @@ func (f *FeatureFlags) SetDefaults() {
|
||||
|
||||
f.MobileEphemeralMode = false
|
||||
|
||||
f.PropertyFieldRank = false
|
||||
f.PropertyFieldRank = true
|
||||
|
||||
f.MmBlocksEnabled = true
|
||||
}
|
||||
|
||||
@@ -60,8 +60,16 @@ func TestFeatureFlagsSetDefaults_AttributeValueMasking(t *testing.T) {
|
||||
var flags FeatureFlags
|
||||
flags.SetDefaults()
|
||||
|
||||
require.False(t, flags.AttributeValueMasking, "AttributeValueMasking should default to false")
|
||||
require.Equal(t, "false", flags.ToMap()["AttributeValueMasking"])
|
||||
require.True(t, flags.AttributeValueMasking, "AttributeValueMasking should default to true")
|
||||
require.Equal(t, "true", flags.ToMap()["AttributeValueMasking"])
|
||||
}
|
||||
|
||||
func TestFeatureFlagsSetDefaults_PropertyFieldRank(t *testing.T) {
|
||||
var flags FeatureFlags
|
||||
flags.SetDefaults()
|
||||
|
||||
require.True(t, flags.PropertyFieldRank, "PropertyFieldRank should default to true")
|
||||
require.Equal(t, "true", flags.ToMap()["PropertyFieldRank"])
|
||||
}
|
||||
|
||||
// TestFeatureFlagsPermissionPoliciesDependencies pins down the
|
||||
@@ -71,12 +79,12 @@ func TestFeatureFlagsSetDefaults_AttributeValueMasking(t *testing.T) {
|
||||
// dependency (additional gates, new sub-flags) only have to update
|
||||
// one place and existing call sites stay correct.
|
||||
func TestFeatureFlagsPermissionPoliciesDependencies(t *testing.T) {
|
||||
t.Run("both helpers are off when defaults are applied", func(t *testing.T) {
|
||||
t.Run("both helpers are on when defaults are applied", func(t *testing.T) {
|
||||
var f FeatureFlags
|
||||
f.SetDefaults()
|
||||
|
||||
require.False(t, f.IsChannelPermissionPoliciesEnabled())
|
||||
require.False(t, f.IsPolicySimulationEnabled())
|
||||
require.True(t, f.IsChannelPermissionPoliciesEnabled())
|
||||
require.True(t, f.IsPolicySimulationEnabled())
|
||||
})
|
||||
|
||||
t.Run("sub-flag alone is not enough — the umbrella must be on too", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user