Skip to content

Commit 6ce5ebb

Browse files
d-bytebaseclaude
andauthored
feat: update to new masking exemption API (#164)
This updates the Terraform provider to use the new protobuf schema and API changes for masking exemption policies. Changes: - Update protobuf dependencies to fb04b193baa94bd0aaca101006b5c9d7 - Rename MASKING_EXCEPTION to MASKING_EXEMPTION throughout - Update API from single Member+Action to Members array model - Remove deprecated actions field completely - Simplify flatten/convert logic to work directly with Members array - Rename all "exception" references to "exemption" in masking context - Update examples, tutorials, and tests to use new API Breaking changes: - masking_exception_policy renamed to masking_exemption_policy - exceptions field renamed to exemptions - actions field removed (no longer supported in API) - API now uses Members array instead of individual Member+Action pairs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent e98604e commit 6ce5ebb

File tree

15 files changed

+159
-200
lines changed

15 files changed

+159
-200
lines changed

docs/data-sources/policy.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The policy data source.
2424

2525
- `data_source_query_policy` (Block List, Max: 1) Restrict querying admin data sources (see [below for nested schema](#nestedblock--data_source_query_policy))
2626
- `global_masking_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--global_masking_policy))
27-
- `masking_exception_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--masking_exception_policy))
27+
- `masking_exemption_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--masking_exemption_policy))
2828
- `query_data_policy` (Block List, Max: 1) The policy for query data (see [below for nested schema](#nestedblock--query_data_policy))
2929
- `rollout_policy` (Block List, Max: 1) Control issue rollout. Learn more: https://docs.bytebase.com/administration/environment-policy/rollout-policy (see [below for nested schema](#nestedblock--rollout_policy))
3030

@@ -67,15 +67,15 @@ Optional:
6767

6868

6969

70-
<a id="nestedblock--masking_exception_policy"></a>
71-
### Nested Schema for `masking_exception_policy`
70+
<a id="nestedblock--masking_exemption_policy"></a>
71+
### Nested Schema for `masking_exemption_policy`
7272

7373
Optional:
7474

75-
- `exceptions` (Block Set) (see [below for nested schema](#nestedblock--masking_exception_policy--exceptions))
75+
- `exemptions` (Block Set) (see [below for nested schema](#nestedblock--masking_exemption_policy--exemptions))
7676

77-
<a id="nestedblock--masking_exception_policy--exceptions"></a>
78-
### Nested Schema for `masking_exception_policy.exceptions`
77+
<a id="nestedblock--masking_exemption_policy--exemptions"></a>
78+
### Nested Schema for `masking_exemption_policy.exemptions`
7979

8080
Required:
8181

@@ -87,7 +87,7 @@ Optional:
8787
- `columns` (Set of String)
8888
- `database` (String) The database full name in instances/{instance resource id}/databases/{database name} format
8989
- `expire_timestamp` (String) The expiration timestamp in YYYY-MM-DDThh:mm:ss.000Z format
90-
- `raw_expression` (String) The raw CEL expression. We will use it as the masking exception and ignore the "database"/"schema"/"table"/"columns"/"expire_timestamp" fields if you provide the raw expression.
90+
- `raw_expression` (String) The raw CEL expression. We will use it as the masking exemption and ignore the "database"/"schema"/"table"/"columns"/"expire_timestamp" fields if you provide the raw expression.
9191
- `reason` (String) The reason for the masking exemption
9292
- `schema` (String)
9393
- `table` (String)

docs/data-sources/policy_list.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Read-Only:
3333
- `enforce` (Boolean)
3434
- `global_masking_policy` (List of Object) (see [below for nested schema](#nestedobjatt--policies--global_masking_policy))
3535
- `inherit_from_parent` (Boolean)
36-
- `masking_exception_policy` (List of Object) (see [below for nested schema](#nestedobjatt--policies--masking_exception_policy))
36+
- `masking_exemption_policy` (List of Object) (see [below for nested schema](#nestedobjatt--policies--masking_exemption_policy))
3737
- `name` (String)
3838
- `query_data_policy` (List of Object) (see [below for nested schema](#nestedobjatt--policies--query_data_policy))
3939
- `rollout_policy` (List of Object) (see [below for nested schema](#nestedobjatt--policies--rollout_policy))
@@ -68,15 +68,15 @@ Read-Only:
6868

6969

7070

71-
<a id="nestedobjatt--policies--masking_exception_policy"></a>
72-
### Nested Schema for `policies.masking_exception_policy`
71+
<a id="nestedobjatt--policies--masking_exemption_policy"></a>
72+
### Nested Schema for `policies.masking_exemption_policy`
7373

7474
Read-Only:
7575

76-
- `exceptions` (Set of Object) (see [below for nested schema](#nestedobjatt--policies--masking_exception_policy--exceptions))
76+
- `exemptions` (Set of Object) (see [below for nested schema](#nestedobjatt--policies--masking_exemption_policy--exemptions))
7777

78-
<a id="nestedobjatt--policies--masking_exception_policy--exceptions"></a>
79-
### Nested Schema for `policies.masking_exception_policy.exceptions`
78+
<a id="nestedobjatt--policies--masking_exemption_policy--exemptions"></a>
79+
### Nested Schema for `policies.masking_exemption_policy.exemptions`
8080

8181
Read-Only:
8282

docs/resources/policy.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The policy resource.
2626
- `enforce` (Boolean) Decide if the policy is enforced.
2727
- `global_masking_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--global_masking_policy))
2828
- `inherit_from_parent` (Boolean) Decide if the policy should inherit from the parent.
29-
- `masking_exception_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--masking_exception_policy))
29+
- `masking_exemption_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--masking_exemption_policy))
3030
- `query_data_policy` (Block List, Max: 1) The policy for query data (see [below for nested schema](#nestedblock--query_data_policy))
3131
- `rollout_policy` (Block List, Max: 1) Control issue rollout. Learn more: https://docs.bytebase.com/administration/environment-policy/rollout-policy (see [below for nested schema](#nestedblock--rollout_policy))
3232

@@ -67,15 +67,15 @@ Optional:
6767

6868

6969

70-
<a id="nestedblock--masking_exception_policy"></a>
71-
### Nested Schema for `masking_exception_policy`
70+
<a id="nestedblock--masking_exemption_policy"></a>
71+
### Nested Schema for `masking_exemption_policy`
7272

7373
Optional:
7474

75-
- `exceptions` (Block Set) (see [below for nested schema](#nestedblock--masking_exception_policy--exceptions))
75+
- `exemptions` (Block Set) (see [below for nested schema](#nestedblock--masking_exemption_policy--exemptions))
7676

77-
<a id="nestedblock--masking_exception_policy--exceptions"></a>
78-
### Nested Schema for `masking_exception_policy.exceptions`
77+
<a id="nestedblock--masking_exemption_policy--exemptions"></a>
78+
### Nested Schema for `masking_exemption_policy.exemptions`
7979

8080
Required:
8181

@@ -87,7 +87,7 @@ Optional:
8787
- `columns` (Set of String)
8888
- `database` (String) The database full name in instances/{instance resource id}/databases/{database name} format
8989
- `expire_timestamp` (String) The expiration timestamp in YYYY-MM-DDThh:mm:ss.000Z format
90-
- `raw_expression` (String) The raw CEL expression. We will use it as the masking exception and ignore the "database"/"schema"/"table"/"columns"/"expire_timestamp" fields if you provide the raw expression.
90+
- `raw_expression` (String) The raw CEL expression. We will use it as the masking exemption and ignore the "database"/"schema"/"table"/"columns"/"expire_timestamp" fields if you provide the raw expression.
9191
- `reason` (String) The reason for the masking exemption
9292
- `schema` (String)
9393
- `table` (String)

examples/policies/main.tf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ provider "bytebase" {
1717
url = "https://bytebase.example.com"
1818
}
1919

20-
data "bytebase_policy" "masking_exception_policy" {
20+
data "bytebase_policy" "masking_exemption_policy" {
2121
parent = "projects/project-sample"
22-
type = "MASKING_EXCEPTION"
22+
type = "MASKING_EXEMPTION"
2323
}
2424

25-
output "masking_exception_policy" {
26-
value = data.bytebase_policy.masking_exception_policy
25+
output "masking_exemption_policy" {
26+
value = data.bytebase_policy.masking_exemption_policy
2727
}
2828

2929
data "bytebase_policy" "global_masking_policy" {

examples/setup/data_masking.tf

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ resource "bytebase_setting" "semantic_types" {
9797
}
9898
}
9999

100-
resource "bytebase_policy" "masking_exception_policy" {
100+
resource "bytebase_policy" "masking_exemption_policy" {
101101
depends_on = [
102102
bytebase_project.sample_project,
103103
bytebase_instance.test,
@@ -106,39 +106,36 @@ resource "bytebase_policy" "masking_exception_policy" {
106106
]
107107

108108
parent = bytebase_project.sample_project.name
109-
type = "MASKING_EXCEPTION"
109+
type = "MASKING_EXEMPTION"
110110
enforce = true
111111
inherit_from_parent = false
112112

113-
masking_exception_policy {
114-
exceptions {
113+
masking_exemption_policy {
114+
exemptions {
115115
database = "instances/test-sample-instance/databases/employee"
116116
table = "salary"
117117
columns = ["amount", "emp_no"]
118118
members = [
119119
format("user:%s", bytebase_user.project_developer.email),
120120
format("user:%s", bytebase_user.workspace_dba.email),
121121
]
122-
actions = ["QUERY", "EXPORT"]
123122
reason = "Grant access"
124123
}
125124

126-
exceptions {
125+
exemptions {
127126
database = "instances/test-sample-instance/databases/employee"
128127
table = "employee"
129128
columns = ["emp_no"]
130129
members = [
131130
format("user:%s", bytebase_user.workspace_dba.email),
132131
]
133-
actions = ["EXPORT"]
134132
reason = "Grant export access"
135133
}
136134

137-
exceptions {
135+
exemptions {
138136
members = [
139137
format("user:%s", bytebase_user.project_developer.email),
140138
]
141-
actions = ["QUERY"]
142139
reason = "Grant query access"
143140
raw_expression = "resource.instance_id == \"test-sample-instance\" && resource.database_name == \"employee\" && resource.table_name == \"employee\" && resource.column_name in [\"first_name\", \"last_name\", \"gender\"]"
144141
}

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ go 1.24.4
55
toolchain go1.24.5
66

77
require (
8-
buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.19.1-20251213023536-6609958f901e.2
9-
buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.11-20251213023536-6609958f901e.1
8+
buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.19.1-20251214112515-fb04b193baa9.2
9+
buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.11-20251214112515-fb04b193baa9.1
1010
connectrpc.com/connect v1.19.1
1111
github.com/hashicorp/go-cty v1.5.0
1212
github.com/hashicorp/terraform-plugin-docs v0.13.0

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20250912141014-52f32327d4b0.1 h1:oKTVB9QIhFBU9y07QCs2lX2EhGkqWKTX3tTOl/ZbU9o=
22
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20250912141014-52f32327d4b0.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM=
3-
buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.19.1-20251213023536-6609958f901e.2 h1:9DZmVi/FAPVp6rGhhznpW7awGgaMPtQ+qbzlg3bzofk=
4-
buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.19.1-20251213023536-6609958f901e.2/go.mod h1:qgJoWoSPMmskQRAk/vKEu8qmskfaLzVgdOoHHcX6XMk=
5-
buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.11-20251213023536-6609958f901e.1 h1:EIfN8MN/kG3Vr7GGUFhMwYrkqbE0N3I2yhOrUSVjwmY=
6-
buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.11-20251213023536-6609958f901e.1/go.mod h1:Y8s/Z9IfQ1KR8k09qLsiYcrIPmozthp/dNL2+/mBCPY=
3+
buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.19.1-20251214112515-fb04b193baa9.2 h1:ZSI0P/0kPFz4JDToqEfEoLxM5Cj9rDeT4B8Setfrtz4=
4+
buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.19.1-20251214112515-fb04b193baa9.2/go.mod h1:HUQjHrRSWi2ed3LvkAu5qrLdm25GT0gs3nwFHT6Fdog=
5+
buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.11-20251214112515-fb04b193baa9.1 h1:hD0jpq7ygiGhM4L3ISRWGx6VHXak1rCh8UadLRSpGaY=
6+
buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.11-20251214112515-fb04b193baa9.1/go.mod h1:Y8s/Z9IfQ1KR8k09qLsiYcrIPmozthp/dNL2+/mBCPY=
77
connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14=
88
connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w=
99
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=

provider/data_source_policy.go

Lines changed: 34 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func dataSourcePolicy() *schema.Resource {
4242
Type: schema.TypeString,
4343
Required: true,
4444
ValidateFunc: validation.StringInSlice([]string{
45-
v1pb.PolicyType_MASKING_EXCEPTION.String(),
45+
v1pb.PolicyType_MASKING_EXEMPTION.String(),
4646
v1pb.PolicyType_MASKING_RULE.String(),
4747
v1pb.PolicyType_DATA_SOURCE_QUERY.String(),
4848
v1pb.PolicyType_ROLLOUT_POLICY.String(),
@@ -65,7 +65,7 @@ func dataSourcePolicy() *schema.Resource {
6565
Computed: true,
6666
Description: "Decide if the policy is enforced.",
6767
},
68-
"masking_exception_policy": getMaskingExceptionPolicySchema(true),
68+
"masking_exemption_policy": getMaskingExemptionPolicySchema(true),
6969
"global_masking_policy": getGlobalMaskingPolicySchema(true),
7070
"data_source_query_policy": getDataSourceQueryPolicySchema(true),
7171
"rollout_policy": getRolloutPolicySchema(true),
@@ -74,7 +74,7 @@ func dataSourcePolicy() *schema.Resource {
7474
}
7575
}
7676

77-
func getMaskingExceptionPolicySchema(computed bool) *schema.Schema {
77+
func getMaskingExemptionPolicySchema(computed bool) *schema.Schema {
7878
return &schema.Schema{
7979
Computed: computed,
8080
Optional: true,
@@ -84,7 +84,7 @@ func getMaskingExceptionPolicySchema(computed bool) *schema.Schema {
8484
MaxItems: 1,
8585
Elem: &schema.Resource{
8686
Schema: map[string]*schema.Schema{
87-
"exceptions": {
87+
"exemptions": {
8888
Computed: computed,
8989
Optional: true,
9090
Default: nil,
@@ -135,19 +135,6 @@ func getMaskingExceptionPolicySchema(computed bool) *schema.Schema {
135135
),
136136
},
137137
},
138-
"actions": {
139-
Type: schema.TypeSet,
140-
Required: true,
141-
MinItems: 1,
142-
Elem: &schema.Schema{
143-
Type: schema.TypeString,
144-
Description: "The action to allow for members. Support QUERY or EXPORT",
145-
ValidateFunc: validation.StringInSlice([]string{
146-
v1pb.MaskingExceptionPolicy_MaskingException_QUERY.String(),
147-
v1pb.MaskingExceptionPolicy_MaskingException_EXPORT.String(),
148-
}, false),
149-
},
150-
},
151138
"reason": {
152139
Type: schema.TypeString,
153140
Optional: true,
@@ -163,11 +150,11 @@ func getMaskingExceptionPolicySchema(computed bool) *schema.Schema {
163150
Type: schema.TypeString,
164151
Computed: computed,
165152
Optional: true,
166-
Description: `The raw CEL expression. We will use it as the masking exception and ignore the "database"/"schema"/"table"/"columns"/"expire_timestamp" fields if you provide the raw expression.`,
153+
Description: `The raw CEL expression. We will use it as the masking exemption and ignore the "database"/"schema"/"table"/"columns"/"expire_timestamp" fields if you provide the raw expression.`,
167154
},
168155
},
169156
},
170-
Set: exceptionHash,
157+
Set: exemptionHash,
171158
},
172159
},
173160
},
@@ -381,13 +368,13 @@ func flattenPolicyPayload(policy *v1pb.Policy) (string, interface{}, diag.Diagno
381368
return "", nil, diag.Errorf("cannot parse name for policy: %s", err.Error())
382369
}
383370
switch policyType {
384-
case v1pb.PolicyType_MASKING_EXCEPTION:
385-
if p := policy.GetMaskingExceptionPolicy(); p != nil {
386-
exceptionPolicy, err := flattenMaskingExceptionPolicy(p)
371+
case v1pb.PolicyType_MASKING_EXEMPTION:
372+
if p := policy.GetMaskingExemptionPolicy(); p != nil {
373+
exemptionPolicy, err := flattenMaskingExemptionPolicy(p)
387374
if err != nil {
388375
return "", nil, diag.FromErr(err)
389376
}
390-
return "masking_exception_policy", exceptionPolicy, nil
377+
return "masking_exemption_policy", exemptionPolicy, nil
391378
}
392379
case v1pb.PolicyType_MASKING_RULE:
393380
if p := policy.GetMaskingRulePolicy(); p != nil {
@@ -469,45 +456,34 @@ func flattenGlobalMaskingPolicy(p *v1pb.MaskingRulePolicy) ([]interface{}, error
469456
return []interface{}{policy}, nil
470457
}
471458

472-
type combineException struct {
473-
expression string
474-
reason string
475-
members []interface{}
476-
actions []interface{}
477-
}
478-
479-
func flattenMaskingExceptionPolicy(p *v1pb.MaskingExceptionPolicy) ([]interface{}, error) {
480-
exceptionList := []interface{}{}
481-
exceptionMap := map[string]*combineException{}
459+
func flattenMaskingExemptionPolicy(p *v1pb.MaskingExemptionPolicy) ([]interface{}, error) {
460+
exemptionList := []interface{}{}
482461

483-
for _, exception := range p.MaskingExceptions {
484-
if exception.Condition == nil || exception.Condition.Expression == "" {
462+
for _, exemption := range p.Exemptions {
463+
if exemption.Condition == nil || exemption.Condition.Expression == "" {
485464
// Skip invalid data.
486465
continue
487466
}
488467

489-
key := fmt.Sprintf("[expression:%s] [reason:%s]", exception.Condition.Expression, exception.Condition.Description)
490-
if _, ok := exceptionMap[key]; !ok {
491-
exceptionMap[key] = &combineException{
492-
expression: exception.Condition.Expression,
493-
reason: exception.Condition.Description,
494-
members: []interface{}{},
495-
actions: []interface{}{},
496-
}
468+
// The new API uses Condition.Title for the reason/description
469+
reason := exemption.Condition.Title
470+
if reason == "" {
471+
reason = exemption.Condition.Description
472+
}
473+
474+
// Convert members to interface slice for schema.Set
475+
members := []interface{}{}
476+
for _, member := range exemption.Members {
477+
members = append(members, member)
497478
}
498-
exceptionMap[key].members = append(exceptionMap[key].members, exception.Member)
499-
exceptionMap[key].actions = append(exceptionMap[key].actions, exception.Action.String())
500-
}
501479

502-
for _, combine := range exceptionMap {
503480
raw := map[string]interface{}{
504-
"members": schema.NewSet(schema.HashString, combine.members),
505-
"actions": schema.NewSet(schema.HashString, combine.actions),
506-
"reason": combine.reason,
507-
"raw_expression": combine.expression,
481+
"members": schema.NewSet(schema.HashString, members),
482+
"reason": reason,
483+
"raw_expression": exemption.Condition.Expression,
508484
}
509485

510-
expressions := strings.Split(combine.expression, " && ")
486+
expressions := strings.Split(exemption.Condition.Expression, " && ")
511487
instanceID := ""
512488
databaseName := ""
513489
columns := []interface{}{}
@@ -571,21 +547,21 @@ func flattenMaskingExceptionPolicy(p *v1pb.MaskingExceptionPolicy) ([]interface{
571547
if len(columns) > 0 {
572548
raw["columns"] = schema.NewSet(schema.HashString, columns)
573549
}
574-
exceptionList = append(exceptionList, raw)
550+
exemptionList = append(exemptionList, raw)
575551
}
576552

577553
policy := map[string]interface{}{
578-
"exceptions": exceptionList,
554+
"exemptions": exemptionList,
579555
}
580556
return []interface{}{policy}, nil
581557
}
582558

583-
func exceptionHash(rawSchema interface{}) int {
584-
exceptions, err := convertToV1Exceptions(rawSchema)
559+
func exemptionHash(rawSchema interface{}) int {
560+
exemptions, err := convertToV1Exemptions(rawSchema)
585561
if err != nil {
586562
return 0
587563
}
588-
return internal.ToHash(&v1pb.MaskingExceptionPolicy{
589-
MaskingExceptions: exceptions,
564+
return internal.ToHash(&v1pb.MaskingExemptionPolicy{
565+
Exemptions: exemptions,
590566
})
591567
}

0 commit comments

Comments
 (0)