From ce1cb7bdf1337fd2c3415e2845de8eccdfcfb52f Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Thu, 9 May 2024 23:06:08 -0700 Subject: [PATCH 1/4] Add compliance security profile setting --- settings/all_settings.go | 2 + ...rce_compliance_security_profile_setting.go | 35 ++++++++ ...ompliance_security_profile_setting_test.go | 87 +++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 settings/resource_compliance_security_profile_setting.go create mode 100644 settings/resource_compliance_security_profile_setting_test.go diff --git a/settings/all_settings.go b/settings/all_settings.go index 50ef2a0b0d..37a5ed9c69 100644 --- a/settings/all_settings.go +++ b/settings/all_settings.go @@ -15,8 +15,10 @@ import ( // 3. Add a new entry to the AllSettingsResources map below. The final resource name will be "databricks__setting". func AllSettingsResources() map[string]common.Resource { return map[string]common.Resource{ +<<<<<<< HEAD "default_namespace": makeSettingResource[settings.DefaultNamespaceSetting, *databricks.WorkspaceClient](defaultNamespaceSetting), "restrict_workspace_admins": makeSettingResource[settings.RestrictWorkspaceAdminsSetting, *databricks.WorkspaceClient](restrictWsAdminsSetting), + "compliance_security_profile_workspace": makeSettingResource[settings.ComplianceSecurityProfileSetting, *databricks.WorkspaceClient](complianceSecurityProfileSetting), "enhanced_security_monitoring_workspace": makeSettingResource[settings.EnhancedSecurityMonitoringSetting, *databricks.WorkspaceClient](enhancedSecurityMonitoringSetting), } } diff --git a/settings/resource_compliance_security_profile_setting.go b/settings/resource_compliance_security_profile_setting.go new file mode 100644 index 0000000000..99cc005bbc --- /dev/null +++ b/settings/resource_compliance_security_profile_setting.go @@ -0,0 +1,35 @@ +package settings + +import ( + "context" + "strings" + + "github.com/databricks/databricks-sdk-go" + "github.com/databricks/databricks-sdk-go/service/settings" +) + +// Enhanced Security Monitoring setting +var complianceSecurityProfileFieldMask = strings.Join([]string{ + "compliance_security_profile_workspace.is_enabled", + "compliance_security_profile_workspace.compliance_standards", +}, ",") +var complianceSecurityProfileSetting = workspaceSetting[settings.ComplianceSecurityProfileSetting]{ + settingStruct: settings.ComplianceSecurityProfileSetting{}, + readFunc: func(ctx context.Context, w *databricks.WorkspaceClient, etag string) (*settings.ComplianceSecurityProfileSetting, error) { + return w.Settings.ComplianceSecurityProfile().Get(ctx, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: etag, + }) + }, + updateFunc: func(ctx context.Context, w *databricks.WorkspaceClient, t settings.ComplianceSecurityProfileSetting) (string, error) { + t.SettingName = "default" + res, err := w.Settings.ComplianceSecurityProfile().Update(ctx, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + Setting: t, + FieldMask: complianceSecurityProfileFieldMask, + }) + if err != nil { + return "", err + } + return res.Etag, err + }, +} \ No newline at end of file diff --git a/settings/resource_compliance_security_profile_setting_test.go b/settings/resource_compliance_security_profile_setting_test.go new file mode 100644 index 0000000000..4e2faba7da --- /dev/null +++ b/settings/resource_compliance_security_profile_setting_test.go @@ -0,0 +1,87 @@ +package settings + +import ( + "testing" + + "github.com/databricks/databricks-sdk-go/apierr" + "github.com/databricks/databricks-sdk-go/experimental/mocks" + "github.com/databricks/databricks-sdk-go/service/settings" + "github.com/databricks/terraform-provider-databricks/qa" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +var testComplianceSecurityProfileSetting = AllSettingsResources()["compliance_security_profile_workspace"] + +func TestQueryCreateComplianceSecurityProfileSettingWithNoneStandard(t *testing.T) { + d, err := qa.ResourceFixture{ + MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) { + e := w.GetMockComplianceSecurityProfileAPI().EXPECT() + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"NONE"}, + }, + SettingName: "default", + }, + }).Return(nil, &apierr.APIError{ + ErrorCode: "NOT_FOUND", + StatusCode: 404, + Message: "SomeMessage", + Details: []apierr.ErrorDetail{{ + Type: "type.googleapis.com/google.rpc.ErrorInfo", + Metadata: map[string]string{ + etagAttrName: "etag1", + }, + }}, + }) + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "etag1", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"NONE"}, + }, + SettingName: "default", + }, + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"NONE"}, + }, + SettingName: "default", + }, nil) + e.Get(mock.Anything, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: "etag2", + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"NONE"}, + }, + SettingName: "default", + }, nil) + }, + Resource: testComplianceSecurityProfileSetting, + Create: true, + HCL: ` + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["NONE"] + } + `, + }.Apply(t) + + assert.NoError(t, err) + + assert.Equal(t, defaultSettingId, d.Id()) + assert.Equal(t, "etag2", d.Get(etagAttrName).(string)) + assert.Equal(t, true, d.Get("compliance_security_profile_workspace.0.is_enabled")) +} \ No newline at end of file From dab645c9e6c0b3155bc31e7cef631d3ec7f0a208 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Thu, 9 May 2024 23:07:21 -0700 Subject: [PATCH 2/4] fmt --- settings/all_settings.go | 1 - .../resource_compliance_security_profile_setting.go | 2 +- ...esource_compliance_security_profile_setting_test.go | 10 +++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/settings/all_settings.go b/settings/all_settings.go index 37a5ed9c69..a01698d6e3 100644 --- a/settings/all_settings.go +++ b/settings/all_settings.go @@ -15,7 +15,6 @@ import ( // 3. Add a new entry to the AllSettingsResources map below. The final resource name will be "databricks__setting". func AllSettingsResources() map[string]common.Resource { return map[string]common.Resource{ -<<<<<<< HEAD "default_namespace": makeSettingResource[settings.DefaultNamespaceSetting, *databricks.WorkspaceClient](defaultNamespaceSetting), "restrict_workspace_admins": makeSettingResource[settings.RestrictWorkspaceAdminsSetting, *databricks.WorkspaceClient](restrictWsAdminsSetting), "compliance_security_profile_workspace": makeSettingResource[settings.ComplianceSecurityProfileSetting, *databricks.WorkspaceClient](complianceSecurityProfileSetting), diff --git a/settings/resource_compliance_security_profile_setting.go b/settings/resource_compliance_security_profile_setting.go index 99cc005bbc..5ab07ddb86 100644 --- a/settings/resource_compliance_security_profile_setting.go +++ b/settings/resource_compliance_security_profile_setting.go @@ -32,4 +32,4 @@ var complianceSecurityProfileSetting = workspaceSetting[settings.ComplianceSecur } return res.Etag, err }, -} \ No newline at end of file +} diff --git a/settings/resource_compliance_security_profile_setting_test.go b/settings/resource_compliance_security_profile_setting_test.go index 4e2faba7da..5e4ee44895 100644 --- a/settings/resource_compliance_security_profile_setting_test.go +++ b/settings/resource_compliance_security_profile_setting_test.go @@ -23,7 +23,7 @@ func TestQueryCreateComplianceSecurityProfileSettingWithNoneStandard(t *testing. Setting: settings.ComplianceSecurityProfileSetting{ Etag: "", ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ - IsEnabled: true, + IsEnabled: true, ComplianceStandards: []settings.ComplianceStandard{"NONE"}, }, SettingName: "default", @@ -45,7 +45,7 @@ func TestQueryCreateComplianceSecurityProfileSettingWithNoneStandard(t *testing. Setting: settings.ComplianceSecurityProfileSetting{ Etag: "etag1", ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ - IsEnabled: true, + IsEnabled: true, ComplianceStandards: []settings.ComplianceStandard{"NONE"}, }, SettingName: "default", @@ -53,7 +53,7 @@ func TestQueryCreateComplianceSecurityProfileSettingWithNoneStandard(t *testing. }).Return(&settings.ComplianceSecurityProfileSetting{ Etag: "etag2", ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ - IsEnabled: true, + IsEnabled: true, ComplianceStandards: []settings.ComplianceStandard{"NONE"}, }, SettingName: "default", @@ -63,7 +63,7 @@ func TestQueryCreateComplianceSecurityProfileSettingWithNoneStandard(t *testing. }).Return(&settings.ComplianceSecurityProfileSetting{ Etag: "etag2", ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ - IsEnabled: true, + IsEnabled: true, ComplianceStandards: []settings.ComplianceStandard{"NONE"}, }, SettingName: "default", @@ -84,4 +84,4 @@ func TestQueryCreateComplianceSecurityProfileSettingWithNoneStandard(t *testing. assert.Equal(t, defaultSettingId, d.Id()) assert.Equal(t, "etag2", d.Get(etagAttrName).(string)) assert.Equal(t, true, d.Get("compliance_security_profile_workspace.0.is_enabled")) -} \ No newline at end of file +} From 900e145acba341ee94f825ee32a94ead82091e4c Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Wed, 15 May 2024 12:12:59 -0700 Subject: [PATCH 3/4] add more tests --- settings/all_settings.go | 2 +- ...ompliance_security_profile_setting_test.go | 173 +++++++++++++++++- 2 files changed, 173 insertions(+), 2 deletions(-) diff --git a/settings/all_settings.go b/settings/all_settings.go index a01698d6e3..b9abe5a641 100644 --- a/settings/all_settings.go +++ b/settings/all_settings.go @@ -17,7 +17,7 @@ func AllSettingsResources() map[string]common.Resource { return map[string]common.Resource{ "default_namespace": makeSettingResource[settings.DefaultNamespaceSetting, *databricks.WorkspaceClient](defaultNamespaceSetting), "restrict_workspace_admins": makeSettingResource[settings.RestrictWorkspaceAdminsSetting, *databricks.WorkspaceClient](restrictWsAdminsSetting), - "compliance_security_profile_workspace": makeSettingResource[settings.ComplianceSecurityProfileSetting, *databricks.WorkspaceClient](complianceSecurityProfileSetting), + "compliance_security_profile_workspace": makeSettingResource[settings.ComplianceSecurityProfileSetting, *databricks.WorkspaceClient](complianceSecurityProfileSetting), "enhanced_security_monitoring_workspace": makeSettingResource[settings.EnhancedSecurityMonitoringSetting, *databricks.WorkspaceClient](enhancedSecurityMonitoringSetting), } } diff --git a/settings/resource_compliance_security_profile_setting_test.go b/settings/resource_compliance_security_profile_setting_test.go index 5e4ee44895..a10a6bae0a 100644 --- a/settings/resource_compliance_security_profile_setting_test.go +++ b/settings/resource_compliance_security_profile_setting_test.go @@ -83,5 +83,176 @@ func TestQueryCreateComplianceSecurityProfileSettingWithNoneStandard(t *testing. assert.Equal(t, defaultSettingId, d.Id()) assert.Equal(t, "etag2", d.Get(etagAttrName).(string)) - assert.Equal(t, true, d.Get("compliance_security_profile_workspace.0.is_enabled")) + res := d.Get("compliance_security_profile_workspace").([]interface{})[0].(map[string]interface{}) + assert.Equal(t, true, res["is_enabled"]) + assert.Equal(t, "NONE", res["compliance_standards"].([]interface{})[0]) + +} + +func TestQueryReadComplianceSecurityProfileSetting(t *testing.T) { + d, err := qa.ResourceFixture{ + MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) { + w.GetMockComplianceSecurityProfileAPI().EXPECT().Get(mock.Anything, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: "etag1", + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, nil) + }, + Resource: testComplianceSecurityProfileSetting, + Read: true, + HCL: ` + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["HIPAA"] + } + etag = "etag1" + `, + ID: defaultSettingId, + }.Apply(t) + + assert.NoError(t, err) + + assert.Equal(t, defaultSettingId, d.Id()) + assert.Equal(t, "etag2", d.Get(etagAttrName).(string)) + res := d.Get("compliance_security_profile_workspace").([]interface{})[0].(map[string]interface{}) + assert.Equal(t, true, res["is_enabled"]) + assert.Equal(t, "HIPAA", res["compliance_standards"].([]interface{})[0]) +} + +func TestQueryUpdateComplianceSecurityProfileSetting(t *testing.T) { + d, err := qa.ResourceFixture{ + MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) { + e := w.GetMockComplianceSecurityProfileAPI().EXPECT() + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "etag1", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA", "PCI_DSS"}, + }, + SettingName: "default", + }, + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA", "PCI_DSS"}, + }, + SettingName: "default", + }, nil) + e.Get(mock.Anything, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: "etag2", + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA", "PCI_DSS"}, + }, + SettingName: "default", + }, nil) + }, + Resource: testComplianceSecurityProfileSetting, + Update: true, + HCL: ` + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["HIPAA", "PCI_DSS"] + } + etag = "etag1" + `, + ID: defaultSettingId, + }.Apply(t) + + assert.NoError(t, err) + + assert.Equal(t, defaultSettingId, d.Id()) + assert.Equal(t, "etag2", d.Get(etagAttrName).(string)) + res := d.Get("compliance_security_profile_workspace").([]interface{})[0].(map[string]interface{}) + assert.Equal(t, true, res["is_enabled"]) + assert.Equal(t, "HIPAA", res["compliance_standards"].([]interface{})[0]) + assert.Equal(t, "PCI_DSS", res["compliance_standards"].([]interface{})[1]) +} + +func TestQueryUpdateComplianceSecurityProfileSettingWithConflict(t *testing.T) { + d, err := qa.ResourceFixture{ + MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) { + e := w.GetMockComplianceSecurityProfileAPI().EXPECT() + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "etag1", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, + }).Return(nil, &apierr.APIError{ + ErrorCode: "RESOURCE_CONFLICT", + StatusCode: 409, + Message: "SomeMessage", + Details: []apierr.ErrorDetail{{ + Type: "type.googleapis.com/google.rpc.ErrorInfo", + Metadata: map[string]string{ + etagAttrName: "etag2", + }, + }}, + }) + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag3", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, nil) + e.Get(mock.Anything, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: "etag3", + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag3", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, nil) + }, + Resource: testComplianceSecurityProfileSetting, + Update: true, + HCL: ` + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["HIPAA"] + } + etag = "etag1" + `, + ID: defaultSettingId, + }.Apply(t) + + assert.NoError(t, err) + + assert.Equal(t, defaultSettingId, d.Id()) + assert.Equal(t, "etag3", d.Get(etagAttrName).(string)) + res := d.Get("compliance_security_profile_workspace").([]interface{})[0].(map[string]interface{}) + assert.Equal(t, true, res["is_enabled"]) + assert.Equal(t, "HIPAA", res["compliance_standards"].([]interface{})[0]) } From a976e1b386f5aeb241aac3929fd02b7a1521db02 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Wed, 15 May 2024 12:24:22 -0700 Subject: [PATCH 4/4] Add doc --- .../compliance_security_profile_setting.md | 37 +++++++++++++++++++ ...ompliance_security_profile_setting_test.go | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 docs/resources/compliance_security_profile_setting.md diff --git a/docs/resources/compliance_security_profile_setting.md b/docs/resources/compliance_security_profile_setting.md new file mode 100644 index 0000000000..7de715dec1 --- /dev/null +++ b/docs/resources/compliance_security_profile_setting.md @@ -0,0 +1,37 @@ +--- +subcategory: "Settings" +--- + +# databricks_compliance_security_profile_workspace_setting Resource + +-> **Note** This resource could be only used with workspace-level provider! + +The `databricks_compliance_security_profile_workspace_setting` resource allows you to control whether to enable the +compliance security profile for the current workspace. Enabling it on a workspace is permanent. By default, it is +turned off. This setting can NOT be disabled once it is enabled. + +## Example Usage + +```hcl +resource "databricks_compliance_security_profile_workspace_setting" "this" { + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["HIPAA", "FEDRAMP_MODERATE"] + } +} +``` + +## Argument Reference + +The resource supports the following arguments: + +* `is_enabled` - (Required) Enable the Compliance Security Profile on the workspace +* `compliance_standards` - (Required) Enable one or more compliance standards on the workspace, e.g. `HIPAA`, `PCI_DSS`, `FEDRAMP_MODERATE` + +## Import + +This resource can be imported by predefined name `global`: + +```bash +terraform import databricks_compliance_security_profile_workspace_setting.this global +``` \ No newline at end of file diff --git a/settings/resource_compliance_security_profile_setting_test.go b/settings/resource_compliance_security_profile_setting_test.go index a10a6bae0a..ec7da734e9 100644 --- a/settings/resource_compliance_security_profile_setting_test.go +++ b/settings/resource_compliance_security_profile_setting_test.go @@ -86,7 +86,7 @@ func TestQueryCreateComplianceSecurityProfileSettingWithNoneStandard(t *testing. res := d.Get("compliance_security_profile_workspace").([]interface{})[0].(map[string]interface{}) assert.Equal(t, true, res["is_enabled"]) assert.Equal(t, "NONE", res["compliance_standards"].([]interface{})[0]) - + } func TestQueryReadComplianceSecurityProfileSetting(t *testing.T) {