Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Masking policy data source v1 #3083

Merged
merged 17 commits into from
Sep 18, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Cleanup
sfc-gh-jmichalak committed Sep 16, 2024
commit 19ddfb7a105761736736bc5b73a51e14c36e4db6
3 changes: 1 addition & 2 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ New fields:
#### *(breaking change)* Renamed fields in snowflake_masking_policy resource
Renamed fields:
- `masking_expression` to `body`
- `return_data_type` to `return_type`
- `signature` to `arguments`
Please rename these fields in your configuration files. State will be migrated automatically.

@@ -26,8 +27,6 @@ The value of these field will be removed from the state automatically.
#### *(breaking change)* Adjusted behavior of arguments/signature
Now, arguments are stored without nested `column` field. Please adjust that in your configs. State is migrated automatically.

Argument names are now case sensitive. All policies created previously in the provider have upper case argument names. If you used lower case before, please adjust your configs. Values in the state will be migrated to uppercase automatically.

#### *(breaking change)* Identifiers related changes
During [identifiers rework](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/ROADMAP.md#identifiers-rework) we decided to
migrate resource ids from pipe-separated to regular Snowflake identifiers (e.g. `<database_name>|<schema_name>` -> `"<database_name>"."<schema_name>"`). Importing resources also needs to be adjusted (see [example](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/resources/row_access_policy#import)).
26 changes: 1 addition & 25 deletions examples/resources/snowflake_masking_policy/resource.tf
Original file line number Diff line number Diff line change
@@ -1,27 +1,3 @@
resource "snowflake_masking_policy" "test" {
name = "EXAMPLE_MASKING_POLICY"
database = "EXAMPLE_DB"
schema = "EXAMPLE_SCHEMA"
signature {
column {
name = "val"
type = "VARCHAR"
}
}
masking_expression = <<-EOF
case
when current_role() in ('ROLE_A') then
val
when is_role_in_session( 'ROLE_B' ) then
'ABC123'
else
'******'
end
EOF

return_data_type = "VARCHAR"
}

# basic resource
resource "snowflake_masking_policy" "test" {
name = "EXAMPLE_ROW_ACCESS_POLICY"
@@ -51,8 +27,8 @@ resource "snowflake_masking_policy" "test" {
EOF
return_data_type = "VARCHAR"
}
# resource with all fields set

# resource with all fields set
resource "snowflake_masking_policy" "test" {
name = "EXAMPLE_ROW_ACCESS_POLICY"
database = "EXAMPLE_DB"
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@ import (
tfconfig "github.com/hashicorp/terraform-plugin-testing/config"
)

// TODO: unify with row access policy
func (p *MaskingPolicyModel) WithArgument(argument []sdk.TableColumnSignature) *MaskingPolicyModel {
maps := make([]config.Variable, len(argument))
for i, v := range argument {

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 7 additions & 12 deletions pkg/acceptance/helpers/masking_policy_client.go
Original file line number Diff line number Diff line change
@@ -26,11 +26,6 @@ func (c *MaskingPolicyClient) client() sdk.MaskingPolicies {
}

func (c *MaskingPolicyClient) CreateMaskingPolicy(t *testing.T) (*sdk.MaskingPolicy, func()) {
t.Helper()
return c.CreateMaskingPolicyInSchema(t, c.ids.SchemaId())
}

func (c *MaskingPolicyClient) CreateMaskingPolicyInSchema(t *testing.T, schemaId sdk.DatabaseObjectIdentifier) (*sdk.MaskingPolicy, func()) {
t.Helper()
signature := []sdk.TableColumnSignature{
{
@@ -43,7 +38,7 @@ func (c *MaskingPolicyClient) CreateMaskingPolicyInSchema(t *testing.T, schemaId
},
}
expression := "REPLACE('X', 1, 2)"
return c.CreateMaskingPolicyWithOptions(t, schemaId, signature, sdk.DataTypeVARCHAR, expression, &sdk.CreateMaskingPolicyOptions{})
return c.CreateMaskingPolicyWithOptions(t, signature, sdk.DataTypeVARCHAR, expression, &sdk.CreateMaskingPolicyOptions{})
}

func (c *MaskingPolicyClient) CreateMaskingPolicyIdentity(t *testing.T, columnType sdk.DataType) (*sdk.MaskingPolicy, func()) {
@@ -56,14 +51,13 @@ func (c *MaskingPolicyClient) CreateMaskingPolicyIdentity(t *testing.T, columnTy
},
}
expression := "a"
return c.CreateMaskingPolicyWithOptions(t, c.ids.SchemaId(), signature, columnType, expression, &sdk.CreateMaskingPolicyOptions{})
return c.CreateMaskingPolicyWithOptions(t, signature, columnType, expression, &sdk.CreateMaskingPolicyOptions{})
}

func (c *MaskingPolicyClient) CreateMaskingPolicyWithOptions(t *testing.T, schemaId sdk.DatabaseObjectIdentifier, signature []sdk.TableColumnSignature, returns sdk.DataType, expression string, options *sdk.CreateMaskingPolicyOptions) (*sdk.MaskingPolicy, func()) {
func (c *MaskingPolicyClient) CreateMaskingPolicyWithOptions(t *testing.T, signature []sdk.TableColumnSignature, returns sdk.DataType, expression string, options *sdk.CreateMaskingPolicyOptions) (*sdk.MaskingPolicy, func()) {
t.Helper()
ctx := context.Background()

id := c.ids.RandomSchemaObjectIdentifierInSchema(schemaId)
id := c.ids.RandomSchemaObjectIdentifier()

err := c.client().Create(ctx, id, signature, returns, expression, options)
require.NoError(t, err)
@@ -74,11 +68,12 @@ func (c *MaskingPolicyClient) CreateMaskingPolicyWithOptions(t *testing.T, schem
return maskingPolicy, c.DropMaskingPolicyFunc(t, id)
}

// TODO: REmove
func (c *MaskingPolicyClient) CreateMaskingPolicyWithOptions2(t *testing.T, id sdk.SchemaObjectIdentifier, signature []sdk.TableColumnSignature, returns sdk.DataType, expression string, options *sdk.CreateMaskingPolicyOptions) (*sdk.MaskingPolicy, func()) {
func (c *MaskingPolicyClient) CreateOrReplaceMaskingPolicyWithOptions(t *testing.T, id sdk.SchemaObjectIdentifier, signature []sdk.TableColumnSignature, returns sdk.DataType, expression string, options *sdk.CreateMaskingPolicyOptions) (*sdk.MaskingPolicy, func()) {
t.Helper()
ctx := context.Background()

options.OrReplace = sdk.Pointer(true)

err := c.client().Create(ctx, id, signature, returns, expression, options)
require.NoError(t, err)

2 changes: 0 additions & 2 deletions pkg/resources/masking_policy.go
Original file line number Diff line number Diff line change
@@ -39,8 +39,6 @@ var maskingPolicySchema = map[string]*schema.Schema{
ForceNew: true,
DiffSuppressFunc: suppressIdentifierQuoting,
},
// TODO (this pr): separate 1st elem?
// TODO (this pr): extract with row access policy
"argument": {
Type: schema.TypeList,
MinItems: 1,
48 changes: 33 additions & 15 deletions pkg/resources/masking_policy_acceptance_test.go
Original file line number Diff line number Diff line change
@@ -27,7 +27,8 @@ func TestAcc_MaskingPolicy_basic(t *testing.T) {
resourceName := "snowflake_masking_policy.test"

body := "case when current_role() in ('ANALYST') then 'true' else 'false' end"
changedBody := "case when current_role() in ('CHANGED') then 'true' else 'false' end"
changedBody := "case when current_role() in ('CHANGED') then 'foo' else 'bar' end"
bodyWithBooleanReturnType := "case when current_role() in ('ANALYST') then true else false end"
argument := []sdk.TableColumnSignature{
{
Name: "A",
@@ -38,6 +39,16 @@ func TestAcc_MaskingPolicy_basic(t *testing.T) {
Type: sdk.DataTypeVARCHAR,
},
}
argumentWithChangedFirstArgumentType := []sdk.TableColumnSignature{
{
Name: "A",
Type: sdk.DataTypeBoolean,
},
{
Name: "B",
Type: sdk.DataTypeVARCHAR,
},
}
changedArgument := []sdk.TableColumnSignature{
{
Name: "C",
@@ -65,6 +76,7 @@ func TestAcc_MaskingPolicy_basic(t *testing.T) {
HasNameString(id.Name()).
HasDatabaseString(id.DatabaseName()).
HasSchemaString(id.SchemaName()).
HasReturnDataTypeString(string(sdk.DataTypeVARCHAR)).
HasFullyQualifiedNameString(id.FullyQualifiedName()).
HasBodyString(body).
HasArguments(argument),
@@ -79,6 +91,7 @@ func TestAcc_MaskingPolicy_basic(t *testing.T) {
HasDatabaseString(id.DatabaseName()).
HasSchemaString(id.SchemaName()).
HasExemptOtherPoliciesString(r.BooleanTrue).
HasReturnDataTypeString(string(sdk.DataTypeVARCHAR)).
HasFullyQualifiedNameString(id.FullyQualifiedName()).
HasCommentString("Terraform acceptance test").
HasBodyString(body).
@@ -102,31 +115,35 @@ func TestAcc_MaskingPolicy_basic(t *testing.T) {
assert.Check(resource.TestCheckResourceAttr(resourceName, "describe_output.0.signature.1.type", string(sdk.DataTypeVARCHAR))),
),
},
// change comment and expression
// change fields
{
ConfigDirectory: acc.ConfigurationDirectory("TestAcc_MaskingPolicy/complete"),
ConfigVariables: tfconfig.ConfigVariablesFromModel(t, policyModel.WithBody(changedBody).WithComment("Terraform acceptance test - changed comment")),
ConfigVariables: tfconfig.ConfigVariablesFromModel(t, policyModel.WithBody(bodyWithBooleanReturnType).WithReturnDataType(string(sdk.DataTypeBoolean)).WithArgument(argumentWithChangedFirstArgumentType).WithComment("Terraform acceptance test - changed comment").WithExemptOtherPolicies(r.BooleanFalse)),
Check: assert.AssertThat(t, resourceassert.MaskingPolicyResource(t, resourceName).
HasNameString(id.Name()).
HasDatabaseString(id.DatabaseName()).
HasSchemaString(id.SchemaName()).
HasReturnDataTypeString(string(sdk.DataTypeBoolean)).
HasFullyQualifiedNameString(id.FullyQualifiedName()).
HasExemptOtherPoliciesString(r.BooleanFalse).
HasCommentString("Terraform acceptance test - changed comment").
HasBodyString(changedBody).
HasArguments(argument),
HasBodyString(bodyWithBooleanReturnType).
HasArguments(argumentWithChangedFirstArgumentType),
),
},
// change signature and comment
// restore previous types - first argument type, return_type, and returned value in `body` must be the same type
{
ConfigDirectory: acc.ConfigurationDirectory("TestAcc_MaskingPolicy/complete"),
ConfigVariables: tfconfig.ConfigVariablesFromModel(t, policyModel.WithArgument(changedArgument)),
ConfigVariables: tfconfig.ConfigVariablesFromModel(t, policyModel.WithBody(body).WithReturnDataType(string(sdk.DataTypeVARCHAR)).WithArgument(changedArgument).WithExemptOtherPolicies(r.BooleanTrue)),
Check: assert.AssertThat(t, resourceassert.MaskingPolicyResource(t, resourceName).
HasNameString(id.Name()).
HasDatabaseString(id.DatabaseName()).
HasSchemaString(id.SchemaName()).
HasReturnDataTypeString(string(sdk.DataTypeVARCHAR)).
HasFullyQualifiedNameString(id.FullyQualifiedName()).
HasExemptOtherPoliciesString(r.BooleanTrue).
HasCommentString("Terraform acceptance test - changed comment").
HasBodyString(changedBody).
HasBodyString(body).
HasArguments(changedArgument),
),
},
@@ -135,9 +152,10 @@ func TestAcc_MaskingPolicy_basic(t *testing.T) {
ConfigDirectory: acc.ConfigurationDirectory("TestAcc_MaskingPolicy/complete"),
ConfigVariables: tfconfig.ConfigVariablesFromModel(t, policyModel),
PreConfig: func() {
acc.TestClient().MaskingPolicy.CreateMaskingPolicyWithOptions2(t, id, argument, sdk.DataTypeVARCHAR, body, &sdk.CreateMaskingPolicyOptions{
Comment: sdk.Pointer("Terraform acceptance test - changed comment"),
OrReplace: sdk.Pointer(true),
acc.TestClient().MaskingPolicy.CreateOrReplaceMaskingPolicyWithOptions(t, id, argument, sdk.DataTypeVARCHAR, body, &sdk.CreateMaskingPolicyOptions{
ExemptOtherPolicies: sdk.Pointer(false),
Comment: sdk.Pointer("Terraform acceptance test - changed comment"),
OrReplace: sdk.Pointer(true),
})
},
ConfigPlanChecks: resource.ConfigPlanChecks{
@@ -151,11 +169,11 @@ func TestAcc_MaskingPolicy_basic(t *testing.T) {
HasSchemaString(id.SchemaName()).
HasFullyQualifiedNameString(id.FullyQualifiedName()).
HasCommentString("Terraform acceptance test - changed comment").
HasBodyString(changedBody).
HasBodyString(body).
HasArguments(changedArgument),
),
},
// external change on body
// external change on body and exempt other policies
{
ConfigDirectory: acc.ConfigurationDirectory("TestAcc_MaskingPolicy/complete"),
ConfigVariables: tfconfig.ConfigVariablesFromModel(t, policyModel),
@@ -172,7 +190,7 @@ func TestAcc_MaskingPolicy_basic(t *testing.T) {
HasSchemaString(id.SchemaName()).
HasFullyQualifiedNameString(id.FullyQualifiedName()).
HasCommentString("Terraform acceptance test - changed comment").
HasBodyString(changedBody).
HasBodyString(body).
HasArguments(changedArgument),
),
},
@@ -199,7 +217,7 @@ func TestAcc_MaskingPolicy_basic(t *testing.T) {
HasSchemaString(id.SchemaName()).
HasFullyQualifiedNameString(id.FullyQualifiedName()).
HasCommentString("").
HasBodyString(changedBody).
HasBodyString(body).
HasArguments(changedArgument),
),
},
2 changes: 1 addition & 1 deletion pkg/resources/row_access_policy.go
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ var rowAccessPolicySchema = map[string]*schema.Schema{
Required: true,
DiffSuppressFunc: NormalizeAndCompare(sdk.ToDataType),
ValidateDiagFunc: sdkValidation(sdk.ToDataType),
Description: "The argument type. VECTOR data types are not yet supported. For more information about data types, check [Snowflake docs](https://docs.snowflake.com/en/sql-reference/intro-summary-data-types).",
Description: dataTypeFieldDescription("The argument type. VECTOR data types are not yet supported."),
ForceNew: true,
},
},
2 changes: 0 additions & 2 deletions pkg/resources/view_acceptance_test.go
Original file line number Diff line number Diff line change
@@ -522,7 +522,6 @@ func TestAcc_View_complete(t *testing.T) {
t.Cleanup(projectionPolicyCleanup)

maskingPolicy, maskingPolicyCleanup := acc.TestClient().MaskingPolicy.CreateMaskingPolicyWithOptions(t,
acc.TestClient().Ids.SchemaId(),
[]sdk.TableColumnSignature{
{
Name: "One",
@@ -677,7 +676,6 @@ func TestAcc_View_columns(t *testing.T) {
statement := fmt.Sprintf("SELECT id, foo FROM %s", table.ID().FullyQualifiedName())

maskingPolicy, maskingPolicyCleanup := acc.TestClient().MaskingPolicy.CreateMaskingPolicyWithOptions(t,
acc.TestClient().Ids.SchemaId(),
[]sdk.TableColumnSignature{
{
Name: "One",
2 changes: 1 addition & 1 deletion pkg/sdk/masking_policy.go
Original file line number Diff line number Diff line change
@@ -373,7 +373,7 @@ func (row maskingPolicyDetailsRow) toMaskingPolicyDetails() *MaskingPolicyDetail
ReturnType: dataType,
Body: row.Body,
}
// TODO (this pr) use/merge with parsing in row access policies
// TODO (after merged changes in row access policies) use/merge with parsing in row access policies
s := strings.Trim(row.Signature, "()")
parts := strings.Split(s, ",")
for _, part := range parts {