diff --git a/README.md b/README.md
index dce551e..9c63dd3 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ using Terraform Bytebase Provider to prepare those instances ready for applicati
- [Go](https://golang.org/doc/install) (1.19 or later)
- [Terraform](https://developer.hashicorp.com/terraform/downloads?product_intent=terraform) (1.3.5 or later)
-- [Bytebase](https://github.com/bytebase/bytebase) (3.10.0 or later)
+- [Bytebase](https://github.com/bytebase/bytebase) (3.11.1 or later)
> If you have problems running `terraform` in MacOS with Apple Silicon, you can following https://stackoverflow.com/questions/66281882/how-can-i-get-terraform-init-to-run-on-my-apple-silicon-macbook-pro-for-the-go and use the `tfenv`.
diff --git a/VERSION b/VERSION
index e0af123..7a82656 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.11.0
\ No newline at end of file
+3.11.1
\ No newline at end of file
diff --git a/docs/data-sources/iam_policy.md b/docs/data-sources/iam_policy.md
index c05a213..46db336 100644
--- a/docs/data-sources/iam_policy.md
+++ b/docs/data-sources/iam_policy.md
@@ -50,7 +50,6 @@ Optional:
- `database` (String) The accessible database full name in instances/{instance resource id}/databases/{database name} format
- `expire_timestamp` (String) The expiration timestamp in YYYY-MM-DDThh:mm:ssZ format
-- `row_limit` (Number) The export row limit for exporter role
- `schema` (String) The accessible schema in the database
- `tables` (Set of String) The accessible table list
diff --git a/docs/data-sources/policy.md b/docs/data-sources/policy.md
index 531daa4..fc119bb 100644
--- a/docs/data-sources/policy.md
+++ b/docs/data-sources/policy.md
@@ -23,7 +23,6 @@ The policy data source.
### Optional
- `data_source_query_policy` (Block List, Max: 1) Restrict querying admin data sources (see [below for nested schema](#nestedblock--data_source_query_policy))
-- `disable_copy_data_policy` (Block List, Max: 1) Restrict data copying in SQL Editor (Admins/DBAs allowed) (see [below for nested schema](#nestedblock--disable_copy_data_policy))
- `global_masking_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--global_masking_policy))
- `masking_exception_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--masking_exception_policy))
- `query_data_policy` (Block List, Max: 1) The policy for query data (see [below for nested schema](#nestedblock--query_data_policy))
@@ -46,14 +45,6 @@ Optional:
- `restriction` (String) RESTRICTION_UNSPECIFIED means no restriction; FALLBACK will allows to query admin data sources when there is no read-only data source; DISALLOW will always disallow to query admin data sources.
-
-### Nested Schema for `disable_copy_data_policy`
-
-Required:
-
-- `enable` (Boolean) Restrict data copying
-
-
### Nested Schema for `global_masking_policy`
@@ -106,12 +97,10 @@ Optional:
### Nested Schema for `query_data_policy`
-Required:
-
-- `disable_export` (Boolean) Disable export data in the SQL editor
-
Optional:
+- `disable_copy_data` (Boolean) Disable copying data in the SQL editor
+- `disable_export` (Boolean) Disable export data in the SQL editor
- `maximum_result_rows` (Number) The return rows limit. If the value <= 0, will be treated as no limit. The default value is -1.
- `maximum_result_size` (Number) The size limit in bytes. The default value is 100MB, we will use the default value if the limit <= 0.
- `timeout_in_seconds` (Number) The maximum time allowed for a query to run in SQL Editor. No limit when the value <= 0
diff --git a/docs/data-sources/policy_list.md b/docs/data-sources/policy_list.md
index 0ed87ff..3135f21 100644
--- a/docs/data-sources/policy_list.md
+++ b/docs/data-sources/policy_list.md
@@ -30,7 +30,6 @@ The policy data source list.
Read-Only:
- `data_source_query_policy` (List of Object) (see [below for nested schema](#nestedobjatt--policies--data_source_query_policy))
-- `disable_copy_data_policy` (List of Object) (see [below for nested schema](#nestedobjatt--policies--disable_copy_data_policy))
- `enforce` (Boolean)
- `global_masking_policy` (List of Object) (see [below for nested schema](#nestedobjatt--policies--global_masking_policy))
- `inherit_from_parent` (Boolean)
@@ -50,14 +49,6 @@ Read-Only:
- `restriction` (String)
-
-### Nested Schema for `policies.disable_copy_data_policy`
-
-Read-Only:
-
-- `enable` (Boolean)
-
-
### Nested Schema for `policies.global_masking_policy`
@@ -106,6 +97,7 @@ Read-Only:
Read-Only:
+- `disable_copy_data` (Boolean)
- `disable_export` (Boolean)
- `maximum_result_rows` (Number)
- `maximum_result_size` (Number)
diff --git a/docs/data-sources/setting.md b/docs/data-sources/setting.md
index 5b22d82..6924a85 100644
--- a/docs/data-sources/setting.md
+++ b/docs/data-sources/setting.md
@@ -214,17 +214,9 @@ Read-Only:
Read-Only:
- `description` (String)
-- `steps` (List of Object) (see [below for nested schema](#nestedobjatt--approval_flow--rules--flow--steps))
+- `roles` (List of String)
- `title` (String)
-
-### Nested Schema for `approval_flow.rules.flow.title`
-
-Read-Only:
-
-- `role` (String)
-
-
diff --git a/docs/resources/iam_policy.md b/docs/resources/iam_policy.md
index 3457946..2b0610b 100644
--- a/docs/resources/iam_policy.md
+++ b/docs/resources/iam_policy.md
@@ -50,7 +50,6 @@ Optional:
- `database` (String) The accessible database full name in instances/{instance resource id}/databases/{database name} format
- `expire_timestamp` (String) The expiration timestamp in YYYY-MM-DDThh:mm:ssZ format
-- `row_limit` (Number) The export row limit for exporter role
- `schema` (String) The accessible schema in the database
- `tables` (Set of String) The accessible table list
diff --git a/docs/resources/policy.md b/docs/resources/policy.md
index a8bbe45..af05cb8 100644
--- a/docs/resources/policy.md
+++ b/docs/resources/policy.md
@@ -23,7 +23,6 @@ The policy resource.
### Optional
- `data_source_query_policy` (Block List, Max: 1) Restrict querying admin data sources (see [below for nested schema](#nestedblock--data_source_query_policy))
-- `disable_copy_data_policy` (Block List, Max: 1) Restrict data copying in SQL Editor (Admins/DBAs allowed) (see [below for nested schema](#nestedblock--disable_copy_data_policy))
- `enforce` (Boolean) Decide if the policy is enforced.
- `global_masking_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--global_masking_policy))
- `inherit_from_parent` (Boolean) Decide if the policy should inherit from the parent.
@@ -46,14 +45,6 @@ Optional:
- `restriction` (String) RESTRICTION_UNSPECIFIED means no restriction; FALLBACK will allows to query admin data sources when there is no read-only data source; DISALLOW will always disallow to query admin data sources.
-
-### Nested Schema for `disable_copy_data_policy`
-
-Required:
-
-- `enable` (Boolean) Restrict data copying
-
-
### Nested Schema for `global_masking_policy`
@@ -106,12 +97,10 @@ Optional:
### Nested Schema for `query_data_policy`
-Required:
-
-- `disable_export` (Boolean) Disable export data in the SQL editor
-
Optional:
+- `disable_copy_data` (Boolean) Disable copying data in the SQL editor
+- `disable_export` (Boolean) Disable export data in the SQL editor
- `maximum_result_rows` (Number) The return rows limit. If the value <= 0, will be treated as no limit. The default value is -1.
- `maximum_result_size` (Number) The size limit in bytes. The default value is 100MB, we will use the default value if the limit <= 0.
- `timeout_in_seconds` (Number) The maximum time allowed for a query to run in SQL Editor. No limit when the value <= 0
diff --git a/docs/resources/risk.md b/docs/resources/risk.md
index 005dc70..138cd0d 100644
--- a/docs/resources/risk.md
+++ b/docs/resources/risk.md
@@ -18,7 +18,7 @@ The risk resource. Require ENTERPRISE subscription. Check the docs https://www.b
### Required
- `condition` (String) The risk condition. Check the proto message https://github.com/bytebase/bytebase/blob/main/proto/v1/v1/risk_service.proto#L210 for details.
-- `level` (Number) The risk level, should be 300, 200 or 100. Higher number means higher level.
+- `level` (String) The risk level. Check https://github.com/bytebase/bytebase/blob/fd87c6bfe8a0d4883f25eb480a3b05ed3c2e1727/proto/v1/v1/common.proto#L93 for details
- `source` (String) The risk source. Check https://github.com/bytebase/bytebase/blob/main/proto/v1/v1/risk_service.proto#L138 for details
- `title` (String) The risk title.
diff --git a/docs/resources/setting.md b/docs/resources/setting.md
index dab9d97..05ae32c 100644
--- a/docs/resources/setting.md
+++ b/docs/resources/setting.md
@@ -55,21 +55,13 @@ Optional:
Required:
-- `steps` (Block List, Min: 1) Approval flow following the step order. (see [below for nested schema](#nestedblock--approval_flow--rules--flow--steps))
+- `roles` (List of String) The role require to review in this step
- `title` (String)
Optional:
- `description` (String)
-
-### Nested Schema for `approval_flow.rules.flow.steps`
-
-Required:
-
-- `role` (String) The role require to review in this step
-
-
### Nested Schema for `approval_flow.rules.conditions`
diff --git a/examples/database/main.tf b/examples/database/main.tf
index e284bb0..2256c83 100644
--- a/examples/database/main.tf
+++ b/examples/database/main.tf
@@ -2,7 +2,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/database_group/main.tf b/examples/database_group/main.tf
index e4083b6..eec14c4 100644
--- a/examples/database_group/main.tf
+++ b/examples/database_group/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
@@ -36,7 +36,7 @@ resource "bytebase_database_group" "databases_in_test" {
resource_id = "databases-in-test"
project = data.bytebase_project.sample_project.name
title = "Databases in test env"
- condition = "resource.environment_name == \"test\""
+ condition = "resource.environment_id == \"test\""
}
data "bytebase_database_group" "databases_in_test" {
diff --git a/examples/environments/main.tf b/examples/environments/main.tf
index b35235a..d9d4310 100644
--- a/examples/environments/main.tf
+++ b/examples/environments/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/groups/main.tf b/examples/groups/main.tf
index 6977b0d..4849143 100644
--- a/examples/groups/main.tf
+++ b/examples/groups/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/iamPolicy/main.tf b/examples/iamPolicy/main.tf
index be14b6a..7872f9f 100644
--- a/examples/iamPolicy/main.tf
+++ b/examples/iamPolicy/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/instances/main.tf b/examples/instances/main.tf
index c2aebd5..f91d42e 100644
--- a/examples/instances/main.tf
+++ b/examples/instances/main.tf
@@ -2,7 +2,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/policies/main.tf b/examples/policies/main.tf
index 6b24618..73ff0fb 100644
--- a/examples/policies/main.tf
+++ b/examples/policies/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/projects/main.tf b/examples/projects/main.tf
index 1c9f744..ee767fc 100644
--- a/examples/projects/main.tf
+++ b/examples/projects/main.tf
@@ -2,7 +2,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/risk/main.tf b/examples/risk/main.tf
index 5592202..234e9c8 100644
--- a/examples/risk/main.tf
+++ b/examples/risk/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/roles/main.tf b/examples/roles/main.tf
index 1ee2b72..8852b38 100644
--- a/examples/roles/main.tf
+++ b/examples/roles/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/settings/main.tf b/examples/settings/main.tf
index fef292f..c98933f 100644
--- a/examples/settings/main.tf
+++ b/examples/settings/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/setup/approval_flow.tf b/examples/setup/approval_flow.tf
index dd59a78..2eba0c8 100644
--- a/examples/setup/approval_flow.tf
+++ b/examples/setup/approval_flow.tf
@@ -7,17 +7,11 @@ resource "bytebase_setting" "approval_flow" {
description = "Need DBA and workspace admin approval"
# Approval flow following the step order.
- steps {
- role = "roles/projectOwner"
- }
-
- steps {
- role = "roles/workspaceDBA"
- }
-
- steps {
- role = "roles/workspaceAdmin"
- }
+ roles = [
+ "roles/projectOwner",
+ "roles/workspaceDBA",
+ "roles/workspaceAdmin"
+ ]
}
# Match any condition will trigger this approval flow.
diff --git a/examples/setup/database_group.tf b/examples/setup/database_group.tf
index 479d08d..5b3737d 100644
--- a/examples/setup/database_group.tf
+++ b/examples/setup/database_group.tf
@@ -4,5 +4,5 @@ resource "bytebase_database_group" "databases_in_test" {
resource_id = "databases-in-test"
project = bytebase_project.sample_project.name
title = "Databases in test env"
- condition = "resource.environment_name == \"test\""
+ condition = "resource.environment_id == \"test\""
}
diff --git a/examples/setup/environment.tf b/examples/setup/environment.tf
index ddbec9b..3c85785 100644
--- a/examples/setup/environment.tf
+++ b/examples/setup/environment.tf
@@ -51,13 +51,13 @@ resource "bytebase_policy" "rollout_policy" {
}
}
-resource "bytebase_policy" "disable_copy_data_policy" {
+resource "bytebase_policy" "env_query_data_policy" {
depends_on = [bytebase_setting.environments]
parent = bytebase_setting.environments.environment_setting[0].environment[0].name
- type = "DISABLE_COPY_DATA"
+ type = "DATA_QUERY"
- disable_copy_data_policy {
- enable = false
+ query_data_policy {
+ disable_copy_data = true
}
}
diff --git a/examples/setup/iam.tf b/examples/setup/iam.tf
index bd11ef9..6f3d382 100644
--- a/examples/setup/iam.tf
+++ b/examples/setup/iam.tf
@@ -80,7 +80,6 @@ resource "bytebase_iam_policy" "project_iam" {
condition {
database = "instances/test-sample-instance/databases/employee"
tables = ["dept_emp", "dept_manager"]
- row_limit = 10000
expire_timestamp = "2027-03-09T16:17:49Z"
}
}
diff --git a/examples/setup/main.tf b/examples/setup/main.tf
index a0a1da6..b82f293 100644
--- a/examples/setup/main.tf
+++ b/examples/setup/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/setup/risk.tf b/examples/setup/risk.tf
index bf5bb5b..b4484f4 100644
--- a/examples/setup/risk.tf
+++ b/examples/setup/risk.tf
@@ -1,7 +1,7 @@
resource "bytebase_risk" "risk" {
title = "Risk for prod environment"
source = "DML"
- level = 300
+ level = "HIGH"
active = true
condition = "resource.environment_id == \"prod\" && statement.affected_rows >= 100"
}
diff --git a/examples/sql_review/main.tf b/examples/sql_review/main.tf
index 11c7506..0c59570 100644
--- a/examples/sql_review/main.tf
+++ b/examples/sql_review/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/users/main.tf b/examples/users/main.tf
index 12a0bac..92907e2 100644
--- a/examples/users/main.tf
+++ b/examples/users/main.tf
@@ -2,7 +2,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/go.mod b/go.mod
index 059001a..ff1a436 100644
--- a/go.mod
+++ b/go.mod
@@ -5,9 +5,9 @@ go 1.24.4
toolchain go1.24.5
require (
- buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.18.1-20250908030532-58bfc338601e.1
- buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.8-20250908030532-58bfc338601e.1
- connectrpc.com/connect v1.18.1
+ buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.19.1-20251010051414-0534aa930702.1
+ buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.10-20251010051414-0534aa930702.1
+ connectrpc.com/connect v1.19.1
github.com/hashicorp/go-cty v1.5.0
github.com/hashicorp/terraform-plugin-docs v0.13.0
github.com/hashicorp/terraform-plugin-log v0.9.0
@@ -15,7 +15,7 @@ require (
github.com/pkg/errors v0.9.1
google.golang.org/genproto v0.0.0-20250528174236-200df99c418a
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822
- google.golang.org/protobuf v1.36.8
+ google.golang.org/protobuf v1.36.10
)
require (
diff --git a/go.sum b/go.sum
index cdb6f53..b5c56b3 100644
--- a/go.sum
+++ b/go.sum
@@ -1,9 +1,9 @@
-buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.18.1-20250908030532-58bfc338601e.1 h1:FQEei3tpJ+OjhAAfLOTzqm+XaFboZI+UpWbXEiQJ1m4=
-buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.18.1-20250908030532-58bfc338601e.1/go.mod h1:/jFGXncqA/NGlTsADOmP7o1PaKo05HUP64uWe4g7UZg=
-buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.8-20250908030532-58bfc338601e.1 h1:9VCImLW8Zda6Tay+4zoS85Y8RwX94/x5XlZeeyQHZ38=
-buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.8-20250908030532-58bfc338601e.1/go.mod h1:dwdKUX0jGgJ7OJe024SNHvANb1TKuBzIrZOzL/3Njtk=
-connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw=
-connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
+buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.19.1-20251010051414-0534aa930702.1 h1:T4v2vd8e4RkC6ccfOdsvmDZ7YnW2YyAT6OFMdwcPgOA=
+buf.build/gen/go/bytebase/bytebase/connectrpc/go v1.19.1-20251010051414-0534aa930702.1/go.mod h1:A57O99YuSmuL9rUI39AMITcbFfJc6Ikv48Qb6Y2EgCw=
+buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.10-20251010051414-0534aa930702.1 h1:5bZgEFfHz4kUG6fkHH9wmBG3dxyaA5rKpaprSP0csTo=
+buf.build/gen/go/bytebase/bytebase/protocolbuffers/go v1.36.10-20251010051414-0534aa930702.1/go.mod h1:hCjM3DsxzHQGb3QEnCNYrln9ZgB16AZLOVfRJZRKC0E=
+connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14=
+connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
@@ -294,8 +294,8 @@ google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
-google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
+google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/provider/data_source_iam_policy.go b/provider/data_source_iam_policy.go
index d9d2a95..52bc8df 100644
--- a/provider/data_source_iam_policy.go
+++ b/provider/data_source_iam_policy.go
@@ -3,12 +3,10 @@ package provider
import (
"context"
"fmt"
- "strconv"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/pkg/errors"
v1pb "buf.build/gen/go/bytebase/bytebase/protocolbuffers/go/v1"
@@ -113,12 +111,6 @@ func getIAMBindingSchema(computed bool) *schema.Schema {
Set: schema.HashString,
Description: "The accessible table list",
},
- "row_limit": {
- Type: schema.TypeInt,
- Computed: computed,
- Optional: true,
- Description: "The export row limit for exporter role",
- },
"expire_timestamp": {
Type: schema.TypeString,
Computed: computed,
@@ -204,13 +196,6 @@ func flattenIAMPolicy(p *v1pb.IamPolicy) ([]interface{}, error) {
}
rawCondition["tables"] = schema.NewSet(schema.HashString, rawTableList)
}
- if strings.HasPrefix(expression, `request.row_limit <= `) {
- i, err := strconv.Atoi(strings.TrimPrefix(expression, `request.row_limit <= `))
- if err != nil {
- return nil, errors.Errorf("cannot convert %s to int with error: %s", expression, err.Error())
- }
- rawCondition["row_limit"] = i
- }
if strings.HasPrefix(expression, "request.time < ") {
rawCondition["expire_timestamp"] = strings.TrimSuffix(
strings.TrimPrefix(expression, `request.time < timestamp("`),
diff --git a/provider/data_source_policy.go b/provider/data_source_policy.go
index 2553ff5..f088398 100644
--- a/provider/data_source_policy.go
+++ b/provider/data_source_policy.go
@@ -44,7 +44,6 @@ func dataSourcePolicy() *schema.Resource {
ValidateFunc: validation.StringInSlice([]string{
v1pb.PolicyType_MASKING_EXCEPTION.String(),
v1pb.PolicyType_MASKING_RULE.String(),
- v1pb.PolicyType_DISABLE_COPY_DATA.String(),
v1pb.PolicyType_DATA_SOURCE_QUERY.String(),
v1pb.PolicyType_ROLLOUT_POLICY.String(),
v1pb.PolicyType_DATA_QUERY.String(),
@@ -68,7 +67,6 @@ func dataSourcePolicy() *schema.Resource {
},
"masking_exception_policy": getMaskingExceptionPolicySchema(true),
"global_masking_policy": getGlobalMaskingPolicySchema(true),
- "disable_copy_data_policy": getDisableCopyDataPolicySchema(true),
"data_source_query_policy": getDataSourceQueryPolicySchema(true),
"rollout_policy": getRolloutPolicySchema(true),
"query_data_policy": getDataQueryPolicySchema(true),
@@ -250,9 +248,14 @@ func getDataQueryPolicySchema(computed bool) *schema.Schema {
},
"disable_export": {
Type: schema.TypeBool,
- Required: true,
+ Optional: true,
Description: "Disable export data in the SQL editor",
},
+ "disable_copy_data": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Description: "Disable copying data in the SQL editor",
+ },
"timeout_in_seconds": {
Type: schema.TypeInt,
Optional: true,
@@ -263,27 +266,6 @@ func getDataQueryPolicySchema(computed bool) *schema.Schema {
}
}
-func getDisableCopyDataPolicySchema(computed bool) *schema.Schema {
- return &schema.Schema{
- Computed: computed,
- Optional: true,
- Default: nil,
- Type: schema.TypeList,
- MinItems: 0,
- MaxItems: 1,
- Description: "Restrict data copying in SQL Editor (Admins/DBAs allowed)",
- Elem: &schema.Resource{
- Schema: map[string]*schema.Schema{
- "enable": {
- Type: schema.TypeBool,
- Required: true,
- Description: "Restrict data copying",
- },
- },
- },
- }
-}
-
func getDataSourceQueryPolicySchema(computed bool) *schema.Schema {
return &schema.Schema{
Computed: computed,
@@ -415,11 +397,6 @@ func flattenPolicyPayload(policy *v1pb.Policy) (string, interface{}, diag.Diagno
}
return "global_masking_policy", maskingPolicy, nil
}
- case v1pb.PolicyType_DISABLE_COPY_DATA:
- if p := policy.GetDisableCopyDataPolicy(); p != nil {
- disableCopyDataPolicy := flattenDisableCopyDataPolicy(p)
- return "disable_copy_data_policy", disableCopyDataPolicy, nil
- }
case v1pb.PolicyType_DATA_SOURCE_QUERY:
if p := policy.GetDataSourceQueryPolicy(); p != nil {
dataSourceQueryPolicy := flattenDataSourceQueryPolicy(p)
@@ -443,7 +420,6 @@ func flattenPolicyPayload(policy *v1pb.Policy) (string, interface{}, diag.Diagno
func flattenRolloutPolicy(p *v1pb.RolloutPolicy) []interface{} {
roles := []string{}
roles = append(roles, p.Roles...)
- roles = append(roles, p.IssueRoles...)
policy := map[string]interface{}{
"automatic": p.Automatic,
"roles": roles,
@@ -460,18 +436,12 @@ func flattenDataSourceQueryPolicy(p *v1pb.DataSourceQueryPolicy) []interface{} {
return []interface{}{policy}
}
-func flattenDisableCopyDataPolicy(p *v1pb.DisableCopyDataPolicy) []interface{} {
- policy := map[string]interface{}{
- "enable": p.Active,
- }
- return []interface{}{policy}
-}
-
func flattenQueryDataPolicy(p *v1pb.QueryDataPolicy) []interface{} {
policy := map[string]interface{}{
"maximum_result_size": int(p.MaximumResultSize),
"maximum_result_rows": int(p.MaximumResultRows),
"disable_export": p.DisableExport,
+ "disable_copy_data": p.DisableCopyData,
"timeout_in_seconds": int(p.Timeout.Seconds),
}
return []interface{}{policy}
diff --git a/provider/data_source_policy_list.go b/provider/data_source_policy_list.go
index 05820ac..36f564c 100644
--- a/provider/data_source_policy_list.go
+++ b/provider/data_source_policy_list.go
@@ -65,7 +65,6 @@ func dataSourcePolicyList() *schema.Resource {
},
"masking_exception_policy": getMaskingExceptionPolicySchema(true),
"global_masking_policy": getGlobalMaskingPolicySchema(true),
- "disable_copy_data_policy": getDisableCopyDataPolicySchema(true),
"data_source_query_policy": getDataSourceQueryPolicySchema(true),
"rollout_policy": getRolloutPolicySchema(true),
"query_data_policy": getDataQueryPolicySchema(true),
diff --git a/provider/data_source_risk.go b/provider/data_source_risk.go
index 2d3b4f7..a52d62b 100644
--- a/provider/data_source_risk.go
+++ b/provider/data_source_risk.go
@@ -30,7 +30,7 @@ func dataSourceRisk() *schema.Resource {
Description: "The risk source.",
},
"level": {
- Type: schema.TypeInt,
+ Type: schema.TypeString,
Computed: true,
Description: "The risk level.",
},
diff --git a/provider/data_source_risk_list.go b/provider/data_source_risk_list.go
index 3089952..1c4ee99 100644
--- a/provider/data_source_risk_list.go
+++ b/provider/data_source_risk_list.go
@@ -37,7 +37,7 @@ func dataSourceRiskList() *schema.Resource {
Description: "The risk source.",
},
"level": {
- Type: schema.TypeInt,
+ Type: schema.TypeString,
Computed: true,
Description: "The risk level.",
},
@@ -75,7 +75,7 @@ func dataSourceRiskListRead(ctx context.Context, d *schema.ResourceData, m inter
raw["name"] = risk.Name
raw["title"] = risk.Title
raw["source"] = risk.Source.String()
- raw["level"] = int(risk.Level)
+ raw["level"] = risk.Level.String()
raw["active"] = risk.Active
raw["condition"] = risk.Condition.Expression
diff --git a/provider/data_source_setting.go b/provider/data_source_setting.go
index 618fc12..9962d95 100644
--- a/provider/data_source_setting.go
+++ b/provider/data_source_setting.go
@@ -503,31 +503,25 @@ func getWorkspaceApprovalSetting(computed bool) *schema.Schema {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"title": {
- Type: schema.TypeString,
- Computed: computed,
- Required: !computed,
+ Type: schema.TypeString,
+ Required: true,
+ ValidateFunc: validation.StringIsNotEmpty,
},
"description": {
Type: schema.TypeString,
Computed: computed,
Optional: true,
},
- "steps": {
+ "roles": {
Type: schema.TypeList,
- Computed: computed,
- Required: !computed,
- Description: "Approval flow following the step order.",
- Elem: &schema.Resource{
- Schema: map[string]*schema.Schema{
- "role": {
- Type: schema.TypeString,
- Required: true,
- ValidateDiagFunc: internal.ResourceNameValidation(
- fmt.Sprintf("^%s", internal.RoleNamePrefix),
- ),
- Description: "The role require to review in this step",
- },
- },
+ Required: true,
+ Description: "The role require to review in this step",
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ Description: `Role full name in roles/{id} format.`,
+ ValidateDiagFunc: internal.ResourceNameValidation(
+ fmt.Sprintf("^%s", internal.RoleNamePrefix),
+ ),
},
},
},
@@ -717,14 +711,9 @@ func parseApprovalExpression(callExpr *v1alpha1.Expr_Call) ([]map[string]interfa
func flattenWorkspaceApprovalSetting(ctx context.Context, client api.Client, setting *v1pb.WorkspaceApprovalSetting) ([]interface{}, error) {
ruleList := []interface{}{}
for _, rule := range setting.Rules {
- stepList := []interface{}{}
- for _, step := range rule.Template.Flow.Steps {
- rawStep := map[string]interface{}{}
- for _, node := range step.Nodes {
- rawStep["role"] = node.Role
- break
- }
- stepList = append(stepList, rawStep)
+ roleList := []interface{}{}
+ for _, role := range rule.Template.Flow.Roles {
+ roleList = append(roleList, role)
}
conditionList := []map[string]interface{}{}
@@ -746,7 +735,7 @@ func flattenWorkspaceApprovalSetting(ctx context.Context, client api.Client, set
map[string]interface{}{
"title": rule.Template.Title,
"description": rule.Template.Description,
- "steps": stepList,
+ "roles": roleList,
},
},
}
diff --git a/provider/internal/mock_client.go b/provider/internal/mock_client.go
index cb59d93..449a4ee 100644
--- a/provider/internal/mock_client.go
+++ b/provider/internal/mock_client.go
@@ -6,6 +6,7 @@ import (
"slices"
"strconv"
"strings"
+ "sync"
"github.com/pkg/errors"
@@ -15,20 +16,23 @@ import (
v1alpha1 "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
-var instanceMap map[string]*v1pb.Instance
-var policyMap map[string]*v1pb.Policy
-var projectMap map[string]*v1pb.Project
-var projectIAMMap map[string]*v1pb.IamPolicy
-var databaseMap map[string]*v1pb.Database
-var databaseCatalogMap map[string]*v1pb.DatabaseCatalog
-var settingMap map[string]*v1pb.Setting
-var userMap map[string]*v1pb.User
-var roleMap map[string]*v1pb.Role
-var groupMap map[string]*v1pb.Group
-var reviewConfigMap map[string]*v1pb.ReviewConfig
-var riskMap map[string]*v1pb.Risk
-var databaseGroupMap map[string]*v1pb.DatabaseGroup
-var workspaceIAMPolicy *v1pb.IamPolicy
+var (
+ mu sync.RWMutex
+ instanceMap map[string]*v1pb.Instance
+ policyMap map[string]*v1pb.Policy
+ projectMap map[string]*v1pb.Project
+ projectIAMMap map[string]*v1pb.IamPolicy
+ databaseMap map[string]*v1pb.Database
+ databaseCatalogMap map[string]*v1pb.DatabaseCatalog
+ settingMap map[string]*v1pb.Setting
+ userMap map[string]*v1pb.User
+ roleMap map[string]*v1pb.Role
+ groupMap map[string]*v1pb.Group
+ reviewConfigMap map[string]*v1pb.ReviewConfig
+ riskMap map[string]*v1pb.Risk
+ databaseGroupMap map[string]*v1pb.DatabaseGroup
+ workspaceIAMPolicy *v1pb.IamPolicy
+)
func init() {
instanceMap = map[string]*v1pb.Instance{}
@@ -77,6 +81,8 @@ type mockClient struct {
// newMockClient returns the new Bytebase API mock client.
func newMockClient(_, _, _ string) (api.Client, error) {
+ mu.RLock()
+ defer mu.RUnlock()
return &mockClient{
instanceMap: instanceMap,
policyMap: policyMap,
@@ -96,6 +102,8 @@ func newMockClient(_, _, _ string) (api.Client, error) {
// ListInstance will return instances in environment.
func (c *mockClient) ListInstance(_ context.Context, filter *api.InstanceFilter) ([]*v1pb.Instance, error) {
+ mu.RLock()
+ defer mu.RUnlock()
instances := make([]*v1pb.Instance, 0)
for _, ins := range c.instanceMap {
if ins.State == v1pb.State_DELETED && filter.State != v1pb.State_DELETED {
@@ -109,6 +117,8 @@ func (c *mockClient) ListInstance(_ context.Context, filter *api.InstanceFilter)
// GetInstance gets the instance by id.
func (c *mockClient) GetInstance(_ context.Context, instanceName string) (*v1pb.Instance, error) {
+ mu.RLock()
+ defer mu.RUnlock()
ins, ok := c.instanceMap[instanceName]
if !ok {
return nil, errors.Errorf("Cannot found instance %s", instanceName)
@@ -166,6 +176,8 @@ func (c *mockClient) CreateInstance(_ context.Context, instanceID string, instan
},
}
+ mu.Lock()
+ defer mu.Unlock()
c.instanceMap[ins.Name] = ins
c.databaseMap[defaultDb.Name] = defaultDb
c.databaseMap[testDb.Name] = testDb
@@ -207,7 +219,9 @@ func (c *mockClient) UpdateInstance(ctx context.Context, patch *v1pb.Instance, u
ins.MaximumConnections = patch.MaximumConnections
}
+ mu.Lock()
c.instanceMap[ins.Name] = ins
+ mu.Unlock()
return ins, nil
}
@@ -219,7 +233,9 @@ func (c *mockClient) DeleteInstance(ctx context.Context, instanceName string) er
}
ins.State = v1pb.State_DELETED
+ mu.Lock()
c.instanceMap[ins.Name] = ins
+ mu.Unlock()
return nil
}
@@ -232,7 +248,9 @@ func (c *mockClient) UndeleteInstance(ctx context.Context, instanceName string)
}
ins.State = v1pb.State_ACTIVE
+ mu.Lock()
c.instanceMap[ins.Name] = ins
+ mu.Unlock()
return ins, nil
}
@@ -244,6 +262,8 @@ func (*mockClient) SyncInstanceSchema(_ context.Context, _ string) error {
// ListPolicies lists policies in a specific resource.
func (c *mockClient) ListPolicies(_ context.Context, parent string) (*v1pb.ListPoliciesResponse, error) {
+ mu.RLock()
+ defer mu.RUnlock()
policies := make([]*v1pb.Policy, 0)
for _, policy := range c.policyMap {
if parent == "" || strings.HasPrefix(policy.Name, parent) {
@@ -258,6 +278,8 @@ func (c *mockClient) ListPolicies(_ context.Context, parent string) (*v1pb.ListP
// GetPolicy gets a policy in a specific resource.
func (c *mockClient) GetPolicy(_ context.Context, policyName string) (*v1pb.Policy, error) {
+ mu.RLock()
+ defer mu.RUnlock()
policy, ok := c.policyMap[policyName]
if !ok {
return nil, errors.Errorf("Cannot found policy %s", policyName)
@@ -273,6 +295,8 @@ func (c *mockClient) UpsertPolicy(_ context.Context, patch *v1pb.Policy, updateM
return nil, err
}
+ mu.Lock()
+ defer mu.Unlock()
policy, existed := c.policyMap[patch.Name]
if !existed {
@@ -335,12 +359,16 @@ func (c *mockClient) UpsertPolicy(_ context.Context, patch *v1pb.Policy, updateM
// DeletePolicy deletes the policy.
func (c *mockClient) DeletePolicy(_ context.Context, policyName string) error {
+ mu.Lock()
+ defer mu.Unlock()
delete(c.policyMap, policyName)
return nil
}
// GetDatabase gets the database by instance resource id and the database name.
func (c *mockClient) GetDatabase(_ context.Context, databaseName string) (*v1pb.Database, error) {
+ mu.RLock()
+ defer mu.RUnlock()
db, ok := c.databaseMap[databaseName]
if !ok {
return nil, errors.Errorf("Cannot found database %s", databaseName)
@@ -351,6 +379,8 @@ func (c *mockClient) GetDatabase(_ context.Context, databaseName string) (*v1pb.
// ListDatabase list the databases.
func (c *mockClient) ListDatabase(_ context.Context, instaceID string, filter *api.DatabaseFilter, _ bool) ([]*v1pb.Database, error) {
+ mu.RLock()
+ defer mu.RUnlock()
projectID := "-"
if filter.Project != "" {
projectID = filter.Project
@@ -381,16 +411,20 @@ func (c *mockClient) UpdateDatabase(ctx context.Context, patch *v1pb.Database, u
if slices.Contains(updateMasks, "labels") {
db.Labels = patch.Labels
}
+ mu.Lock()
c.databaseMap[db.Name] = db
+ mu.Unlock()
return db, nil
}
// BatchUpdateDatabases batch updates databases.
-func (c *mockClient) BatchUpdateDatabases(ctx context.Context, request *v1pb.BatchUpdateDatabasesRequest) (*v1pb.BatchUpdateDatabasesResponse, error) {
+func (c *mockClient) BatchUpdateDatabases(_ context.Context, request *v1pb.BatchUpdateDatabasesRequest) (*v1pb.BatchUpdateDatabasesResponse, error) {
+ mu.Lock()
+ defer mu.Unlock()
for _, req := range request.Requests {
- db, err := c.GetDatabase(ctx, req.Database.Name)
- if err != nil {
- return nil, err
+ db, ok := c.databaseMap[req.Database.Name]
+ if !ok {
+ return nil, errors.Errorf("Cannot found database %s", req.Database.Name)
}
if slices.Contains(req.UpdateMask.Paths, "project") {
db.Project = req.Database.Project
@@ -403,6 +437,8 @@ func (c *mockClient) BatchUpdateDatabases(ctx context.Context, request *v1pb.Bat
// GetDatabaseCatalog gets the database catalog by the database full name.
func (c *mockClient) GetDatabaseCatalog(_ context.Context, databaseName string) (*v1pb.DatabaseCatalog, error) {
+ mu.RLock()
+ defer mu.RUnlock()
db, ok := c.databaseCatalogMap[databaseName]
if !ok {
return nil, errors.Errorf("Cannot found database catalog %s", databaseName)
@@ -413,12 +449,16 @@ func (c *mockClient) GetDatabaseCatalog(_ context.Context, databaseName string)
// UpdateDatabaseCatalog patches the database catalog.
func (c *mockClient) UpdateDatabaseCatalog(_ context.Context, patch *v1pb.DatabaseCatalog) (*v1pb.DatabaseCatalog, error) {
+ mu.Lock()
+ defer mu.Unlock()
c.databaseCatalogMap[patch.Name] = patch
return patch, nil
}
// GetProject gets the project by resource id.
func (c *mockClient) GetProject(_ context.Context, projectName string) (*v1pb.Project, error) {
+ mu.RLock()
+ defer mu.RUnlock()
proj, ok := c.projectMap[projectName]
if !ok {
return nil, errors.Errorf("Cannot found project %s", projectName)
@@ -429,6 +469,8 @@ func (c *mockClient) GetProject(_ context.Context, projectName string) (*v1pb.Pr
// ListProject list the projects.
func (c *mockClient) ListProject(_ context.Context, filter *api.ProjectFilter) ([]*v1pb.Project, error) {
+ mu.RLock()
+ defer mu.RUnlock()
projects := make([]*v1pb.Project, 0)
for _, proj := range c.projectMap {
if proj.State == v1pb.State_DELETED && filter.State != v1pb.State_DELETED {
@@ -442,6 +484,8 @@ func (c *mockClient) ListProject(_ context.Context, filter *api.ProjectFilter) (
// CreateProject creates the project.
func (c *mockClient) CreateProject(_ context.Context, projectID string, project *v1pb.Project) (*v1pb.Project, error) {
+ mu.Lock()
+ defer mu.Unlock()
proj := &v1pb.Project{
Name: fmt.Sprintf("%s%s", ProjectNamePrefix, projectID),
State: v1pb.State_ACTIVE,
@@ -463,7 +507,9 @@ func (c *mockClient) UpdateProject(ctx context.Context, patch *v1pb.Project, upd
proj.Title = patch.Title
}
+ mu.Lock()
c.projectMap[proj.Name] = proj
+ mu.Unlock()
return proj, nil
}
@@ -475,7 +521,9 @@ func (c *mockClient) DeleteProject(ctx context.Context, projectName string) erro
}
proj.State = v1pb.State_DELETED
+ mu.Lock()
c.projectMap[proj.Name] = proj
+ mu.Unlock()
return nil
}
@@ -488,13 +536,17 @@ func (c *mockClient) UndeleteProject(ctx context.Context, projectName string) (*
}
proj.State = v1pb.State_ACTIVE
+ mu.Lock()
c.projectMap[proj.Name] = proj
+ mu.Unlock()
return proj, nil
}
// GetProjectIAMPolicy gets the project IAM policy by project full name.
func (c *mockClient) GetProjectIAMPolicy(_ context.Context, projectName string) (*v1pb.IamPolicy, error) {
+ mu.RLock()
+ defer mu.RUnlock()
iamPolicy, ok := c.projectIAMMap[projectName]
if !ok {
return &v1pb.IamPolicy{}, nil
@@ -504,12 +556,16 @@ func (c *mockClient) GetProjectIAMPolicy(_ context.Context, projectName string)
// SetProjectIAMPolicy sets the project IAM policy.
func (c *mockClient) SetProjectIAMPolicy(_ context.Context, projectName string, update *v1pb.SetIamPolicyRequest) (*v1pb.IamPolicy, error) {
+ mu.Lock()
+ defer mu.Unlock()
c.projectIAMMap[projectName] = update.Policy
return c.projectIAMMap[projectName], nil
}
// ListSettings lists all settings.
func (c *mockClient) ListSettings(_ context.Context) (*v1pb.ListSettingsResponse, error) {
+ mu.RLock()
+ defer mu.RUnlock()
settings := make([]*v1pb.Setting, 0)
for _, setting := range c.settingMap {
settings = append(settings, setting)
@@ -522,6 +578,8 @@ func (c *mockClient) ListSettings(_ context.Context) (*v1pb.ListSettingsResponse
// ListSettings lists all settings.
func (c *mockClient) GetSetting(_ context.Context, settingName string) (*v1pb.Setting, error) {
+ mu.RLock()
+ defer mu.RUnlock()
setting, ok := c.settingMap[settingName]
if !ok {
return nil, errors.Errorf("Cannot found setting %s", settingName)
@@ -532,6 +590,8 @@ func (c *mockClient) GetSetting(_ context.Context, settingName string) (*v1pb.Se
// UpsertSetting updates or creates the setting.
func (c *mockClient) UpsertSetting(_ context.Context, upsert *v1pb.Setting, _ []string) (*v1pb.Setting, error) {
+ mu.Lock()
+ defer mu.Unlock()
setting, ok := c.settingMap[upsert.Name]
if !ok {
c.settingMap[upsert.Name] = upsert
@@ -685,6 +745,8 @@ func parseCondition(condition string, baseID int64) *v1alpha1.Expr {
// ListUser list all users.
func (c *mockClient) ListUser(_ context.Context, filter *api.UserFilter) ([]*v1pb.User, error) {
+ mu.RLock()
+ defer mu.RUnlock()
users := make([]*v1pb.User, 0)
for _, user := range c.userMap {
if user.State == v1pb.State_DELETED && filter.State != v1pb.State_DELETED {
@@ -698,6 +760,8 @@ func (c *mockClient) ListUser(_ context.Context, filter *api.UserFilter) ([]*v1p
// GetUser gets the user by name.
func (c *mockClient) GetUser(_ context.Context, userName string) (*v1pb.User, error) {
+ mu.RLock()
+ defer mu.RUnlock()
user, ok := c.userMap[userName]
if !ok {
return nil, errors.Errorf("Cannot found user %s", userName)
@@ -709,6 +773,8 @@ func (c *mockClient) GetUser(_ context.Context, userName string) (*v1pb.User, er
// CreateUser creates the user.
func (c *mockClient) CreateUser(_ context.Context, user *v1pb.User) (*v1pb.User, error) {
// For service accounts, generate a service key
+ mu.Lock()
+ defer mu.Unlock()
if user.UserType == v1pb.UserType_SERVICE_ACCOUNT && user.ServiceKey == "" {
user.ServiceKey = fmt.Sprintf("bbs_%s_mock_service_key", strings.ReplaceAll(user.Email, "@", "_"))
}
@@ -735,7 +801,9 @@ func (c *mockClient) UpdateUser(ctx context.Context, user *v1pb.User, updateMask
if slices.Contains(updateMasks, "phone") {
existed.Phone = user.Phone
}
+ mu.Lock()
c.userMap[user.Name] = existed
+ mu.Unlock()
return c.userMap[user.Name], nil
}
@@ -747,7 +815,9 @@ func (c *mockClient) DeleteUser(ctx context.Context, userName string) error {
}
user.State = v1pb.State_DELETED
+ mu.Lock()
c.userMap[user.Name] = user
+ mu.Unlock()
return nil
}
@@ -760,13 +830,17 @@ func (c *mockClient) UndeleteUser(ctx context.Context, userName string) (*v1pb.U
}
user.State = v1pb.State_ACTIVE
+ mu.Lock()
c.userMap[user.Name] = user
+ mu.Unlock()
return c.userMap[user.Name], nil
}
// ListGroup list all groups.
func (c *mockClient) ListGroup(_ context.Context, _ *api.GroupFilter) ([]*v1pb.Group, error) {
+ mu.RLock()
+ defer mu.RUnlock()
groups := make([]*v1pb.Group, 0)
for _, group := range c.groupMap {
groups = append(groups, group)
@@ -777,6 +851,8 @@ func (c *mockClient) ListGroup(_ context.Context, _ *api.GroupFilter) ([]*v1pb.G
// GetGroup gets the group by name.
func (c *mockClient) GetGroup(_ context.Context, name string) (*v1pb.Group, error) {
+ mu.RLock()
+ defer mu.RUnlock()
group, ok := c.groupMap[name]
if !ok {
return nil, errors.Errorf("Cannot found group %s", name)
@@ -787,6 +863,8 @@ func (c *mockClient) GetGroup(_ context.Context, name string) (*v1pb.Group, erro
// CreateGroup creates the group.
func (c *mockClient) CreateGroup(_ context.Context, email string, group *v1pb.Group) (*v1pb.Group, error) {
+ mu.Lock()
+ defer mu.Unlock()
groupName := fmt.Sprintf("%s%s", GroupNamePrefix, email)
group.Name = groupName
c.groupMap[groupName] = group
@@ -808,23 +886,31 @@ func (c *mockClient) UpdateGroup(ctx context.Context, group *v1pb.Group, updateM
if slices.Contains(updateMasks, "members") {
existed.Members = group.Members
}
+ mu.Lock()
c.groupMap[existed.Name] = existed
+ mu.Unlock()
return existed, nil
}
// DeleteGroup deletes the group by name.
func (c *mockClient) DeleteGroup(_ context.Context, name string) error {
+ mu.Lock()
+ defer mu.Unlock()
delete(c.groupMap, name)
return nil
}
// GetWorkspaceIAMPolicy gets the workspace IAM policy.
func (*mockClient) GetWorkspaceIAMPolicy(_ context.Context) (*v1pb.IamPolicy, error) {
+ mu.RLock()
+ defer mu.RUnlock()
return workspaceIAMPolicy, nil
}
// SetWorkspaceIAMPolicy sets the workspace IAM policy.
func (*mockClient) SetWorkspaceIAMPolicy(_ context.Context, update *v1pb.SetIamPolicyRequest) (*v1pb.IamPolicy, error) {
+ mu.Lock()
+ defer mu.Unlock()
if v := update.Policy; v != nil {
workspaceIAMPolicy = v
}
@@ -833,6 +919,8 @@ func (*mockClient) SetWorkspaceIAMPolicy(_ context.Context, update *v1pb.SetIamP
// ListRole will returns all roles.
func (c *mockClient) ListRole(_ context.Context) (*v1pb.ListRolesResponse, error) {
+ mu.RLock()
+ defer mu.RUnlock()
roles := make([]*v1pb.Role, 0)
for _, role := range c.roleMap {
roles = append(roles, role)
@@ -845,6 +933,8 @@ func (c *mockClient) ListRole(_ context.Context) (*v1pb.ListRolesResponse, error
// GetRole gets the role by full name.
func (c *mockClient) GetRole(_ context.Context, roleName string) (*v1pb.Role, error) {
+ mu.RLock()
+ defer mu.RUnlock()
role, ok := c.roleMap[roleName]
if !ok {
return nil, errors.Errorf("Cannot found role %s", roleName)
@@ -855,6 +945,8 @@ func (c *mockClient) GetRole(_ context.Context, roleName string) (*v1pb.Role, er
// CreateRole creates the role.
func (c *mockClient) CreateRole(_ context.Context, roleID string, role *v1pb.Role) (*v1pb.Role, error) {
+ mu.Lock()
+ defer mu.Unlock()
roleName := fmt.Sprintf("%s%s", RoleNamePrefix, roleID)
role.Name = roleName
c.roleMap[roleName] = role
@@ -876,18 +968,24 @@ func (c *mockClient) UpdateRole(ctx context.Context, role *v1pb.Role, updateMask
if slices.Contains(updateMasks, "permissions") {
existed.Permissions = role.Permissions
}
+ mu.Lock()
c.roleMap[existed.Name] = existed
+ mu.Unlock()
return c.roleMap[existed.Name], nil
}
// DeleteRole deletes the role by name.
func (c *mockClient) DeleteRole(_ context.Context, roleName string) error {
+ mu.Lock()
+ defer mu.Unlock()
delete(c.roleMap, roleName)
return nil
}
// ListReviewConfig will return review configs.
func (c *mockClient) ListReviewConfig(_ context.Context) (*v1pb.ListReviewConfigsResponse, error) {
+ mu.RLock()
+ defer mu.RUnlock()
configs := make([]*v1pb.ReviewConfig, 0)
for _, config := range c.reviewConfigMap {
configs = append(configs, config)
@@ -899,6 +997,8 @@ func (c *mockClient) ListReviewConfig(_ context.Context) (*v1pb.ListReviewConfig
// GetReviewConfig gets the review config by full name.
func (c *mockClient) GetReviewConfig(_ context.Context, reviewConfigName string) (*v1pb.ReviewConfig, error) {
+ mu.RLock()
+ defer mu.RUnlock()
config, ok := c.reviewConfigMap[reviewConfigName]
if !ok {
return nil, errors.Errorf("Cannot found review config %s", reviewConfigName)
@@ -908,6 +1008,8 @@ func (c *mockClient) GetReviewConfig(_ context.Context, reviewConfigName string)
// UpsertReviewConfig updates or creates the review config.
func (c *mockClient) UpsertReviewConfig(_ context.Context, reviewConfig *v1pb.ReviewConfig, updateMasks []string) (*v1pb.ReviewConfig, error) {
+ mu.Lock()
+ defer mu.Unlock()
existed, ok := c.reviewConfigMap[reviewConfig.Name]
if !ok {
// Create new review config
@@ -936,12 +1038,16 @@ func (c *mockClient) UpsertReviewConfig(_ context.Context, reviewConfig *v1pb.Re
// DeleteReviewConfig deletes the review config.
func (c *mockClient) DeleteReviewConfig(_ context.Context, reviewConfigName string) error {
+ mu.Lock()
+ defer mu.Unlock()
delete(c.reviewConfigMap, reviewConfigName)
return nil
}
// ListRisk lists the risk.
func (c *mockClient) ListRisk(_ context.Context) ([]*v1pb.Risk, error) {
+ mu.RLock()
+ defer mu.RUnlock()
risks := make([]*v1pb.Risk, 0)
for _, risk := range c.riskMap {
risks = append(risks, risk)
@@ -951,6 +1057,8 @@ func (c *mockClient) ListRisk(_ context.Context) ([]*v1pb.Risk, error) {
// GetRisk gets the risk by full name.
func (c *mockClient) GetRisk(_ context.Context, riskName string) (*v1pb.Risk, error) {
+ mu.RLock()
+ defer mu.RUnlock()
risk, ok := c.riskMap[riskName]
if !ok {
return nil, errors.Errorf("Cannot found risk %s", riskName)
@@ -961,6 +1069,8 @@ func (c *mockClient) GetRisk(_ context.Context, riskName string) (*v1pb.Risk, er
// CreateRisk creates the risk.
func (c *mockClient) CreateRisk(_ context.Context, risk *v1pb.Risk) (*v1pb.Risk, error) {
// Generate a unique name for the risk if not set
+ mu.Lock()
+ defer mu.Unlock()
if risk.Name == "" {
risk.Name = fmt.Sprintf("risks/%d", len(c.riskMap)+1)
}
@@ -973,6 +1083,8 @@ func (c *mockClient) CreateRisk(_ context.Context, risk *v1pb.Risk) (*v1pb.Risk,
// UpdateRisk updates the risk.
func (c *mockClient) UpdateRisk(_ context.Context, risk *v1pb.Risk, updateMasks []string) (*v1pb.Risk, error) {
+ mu.Lock()
+ defer mu.Unlock()
existed, ok := c.riskMap[risk.Name]
if !ok {
return nil, errors.Errorf("Cannot found risk %s", risk.Name)
@@ -997,6 +1109,8 @@ func (c *mockClient) UpdateRisk(_ context.Context, risk *v1pb.Risk, updateMasks
// DeleteRisk deletes the risk by name.
func (c *mockClient) DeleteRisk(_ context.Context, riskName string) error {
+ mu.Lock()
+ defer mu.Unlock()
delete(c.riskMap, riskName)
return nil
}
@@ -1023,6 +1137,8 @@ func FindEnvironment(ctx context.Context, client api.Client, name string) (*v1pb
// ListDatabaseGroup list all database groups in a project.
func (c *mockClient) ListDatabaseGroup(_ context.Context, projectName string) (*v1pb.ListDatabaseGroupsResponse, error) {
+ mu.RLock()
+ defer mu.RUnlock()
groups := make([]*v1pb.DatabaseGroup, 0)
for name, group := range c.databaseGroupMap {
// Only return groups that belong to the specified project
@@ -1037,6 +1153,8 @@ func (c *mockClient) ListDatabaseGroup(_ context.Context, projectName string) (*
// GetDatabaseGroup gets the database group by name.
func (c *mockClient) GetDatabaseGroup(_ context.Context, groupName string, _ v1pb.DatabaseGroupView) (*v1pb.DatabaseGroup, error) {
+ mu.RLock()
+ defer mu.RUnlock()
group, ok := c.databaseGroupMap[groupName]
if !ok {
return nil, errors.Errorf("Cannot found database group %s", groupName)
@@ -1046,6 +1164,8 @@ func (c *mockClient) GetDatabaseGroup(_ context.Context, groupName string, _ v1p
// CreateDatabaseGroup creates the database group.
func (c *mockClient) CreateDatabaseGroup(_ context.Context, projectID, groupID string, group *v1pb.DatabaseGroup) (*v1pb.DatabaseGroup, error) {
+ mu.Lock()
+ defer mu.Unlock()
groupName := fmt.Sprintf("%s%s/databaseGroups/%s", ProjectNamePrefix, projectID, groupID)
group.Name = groupName
if _, exists := c.databaseGroupMap[groupName]; exists {
@@ -1057,6 +1177,8 @@ func (c *mockClient) CreateDatabaseGroup(_ context.Context, projectID, groupID s
// UpdateDatabaseGroup updates the database group.
func (c *mockClient) UpdateDatabaseGroup(_ context.Context, group *v1pb.DatabaseGroup, updateMasks []string) (*v1pb.DatabaseGroup, error) {
+ mu.Lock()
+ defer mu.Unlock()
existed, ok := c.databaseGroupMap[group.Name]
if !ok {
return nil, errors.Errorf("Cannot found database group %s", group.Name)
@@ -1070,9 +1192,6 @@ func (c *mockClient) UpdateDatabaseGroup(_ context.Context, group *v1pb.Database
if slices.Contains(updateMasks, "matched_databases") {
existed.MatchedDatabases = group.MatchedDatabases
}
- if slices.Contains(updateMasks, "unmatched_databases") {
- existed.UnmatchedDatabases = group.UnmatchedDatabases
- }
c.databaseGroupMap[group.Name] = existed
return existed, nil
@@ -1080,6 +1199,8 @@ func (c *mockClient) UpdateDatabaseGroup(_ context.Context, group *v1pb.Database
// DeleteDatabaseGroup deletes the database group by name.
func (c *mockClient) DeleteDatabaseGroup(_ context.Context, groupName string) error {
+ mu.Lock()
+ defer mu.Unlock()
delete(c.databaseGroupMap, groupName)
return nil
}
diff --git a/provider/resource_iam_policy.go b/provider/resource_iam_policy.go
index 8de33df..18e4111 100644
--- a/provider/resource_iam_policy.go
+++ b/provider/resource_iam_policy.go
@@ -143,9 +143,6 @@ func convertToV1Condition(rawSchema interface{}) (*expr.Expr, error) {
}
expressions = append(expressions, fmt.Sprintf(`resource.table_name in [%s]`, strings.Join(tableList, ",")))
}
- if rowLimit, ok := rawCondition["row_limit"].(int); ok && rowLimit > 0 {
- expressions = append(expressions, fmt.Sprintf(`request.row_limit <= %d`, rowLimit))
- }
if expire, ok := rawCondition["expire_timestamp"].(string); ok && expire != "" {
formattedTime, err := time.Parse(time.RFC3339, expire)
if err != nil {
diff --git a/provider/resource_policy.go b/provider/resource_policy.go
index c8eaf6a..4845da1 100644
--- a/provider/resource_policy.go
+++ b/provider/resource_policy.go
@@ -54,7 +54,6 @@ func resourcePolicy() *schema.Resource {
ValidateFunc: validation.StringInSlice([]string{
v1pb.PolicyType_MASKING_EXCEPTION.String(),
v1pb.PolicyType_MASKING_RULE.String(),
- v1pb.PolicyType_DISABLE_COPY_DATA.String(),
v1pb.PolicyType_DATA_SOURCE_QUERY.String(),
v1pb.PolicyType_ROLLOUT_POLICY.String(),
v1pb.PolicyType_DATA_QUERY.String(),
@@ -80,7 +79,6 @@ func resourcePolicy() *schema.Resource {
},
"masking_exception_policy": getMaskingExceptionPolicySchema(false),
"global_masking_policy": getGlobalMaskingPolicySchema(false),
- "disable_copy_data_policy": getDisableCopyDataPolicySchema(false),
"data_source_query_policy": getDataSourceQueryPolicySchema(false),
"rollout_policy": getRolloutPolicySchema(false),
"query_data_policy": getDataQueryPolicySchema(false),
@@ -153,18 +151,6 @@ func resourcePolicyCreate(ctx context.Context, d *schema.ResourceData, m interfa
MaskingRulePolicy: maskingRulePolicy,
}
updateMasks = append(updateMasks, "masking_rule_policy")
- case v1pb.PolicyType_DISABLE_COPY_DATA:
- if !strings.HasPrefix(policyName, internal.EnvironmentNamePrefix) && !strings.HasPrefix(policyName, internal.ProjectNamePrefix) {
- return diag.Errorf("policy %v only support environment or project resource", policyName)
- }
- disableCopyDataPolicy, err := convertToDisableCopyDataPolicy(d)
- if err != nil {
- return diag.FromErr(err)
- }
- patch.Policy = &v1pb.Policy_DisableCopyDataPolicy{
- DisableCopyDataPolicy: disableCopyDataPolicy,
- }
- updateMasks = append(updateMasks, "disable_copy_data_policy")
case v1pb.PolicyType_DATA_SOURCE_QUERY:
if !strings.HasPrefix(policyName, internal.EnvironmentNamePrefix) && !strings.HasPrefix(policyName, internal.ProjectNamePrefix) {
return diag.Errorf("policy %v only support environment or project resource", policyName)
@@ -190,8 +176,8 @@ func resourcePolicyCreate(ctx context.Context, d *schema.ResourceData, m interfa
}
updateMasks = append(updateMasks, "rollout_policy")
case v1pb.PolicyType_DATA_QUERY:
- if parent != internal.WorkspaceName {
- return diag.Errorf("policy %v only support %v parent", policyName, internal.WorkspaceName)
+ if parent != internal.WorkspaceName && !strings.HasPrefix(policyName, internal.EnvironmentNamePrefix) {
+ return diag.Errorf("policy %v only support %v or environment resource", policyName, internal.WorkspaceName)
}
queryDataPolicy, err := convertToQueryDataPolicy(d)
if err != nil {
@@ -282,16 +268,6 @@ func resourcePolicyUpdate(ctx context.Context, d *schema.ResourceData, m interfa
MaskingRulePolicy: maskingRulePolicy,
}
}
- if d.HasChange("disable_copy_data_policy") {
- updateMasks = append(updateMasks, "disable_copy_data_policy")
- disableCopyDataPolicy, err := convertToDisableCopyDataPolicy(d)
- if err != nil {
- return diag.FromErr(err)
- }
- patch.Policy = &v1pb.Policy_DisableCopyDataPolicy{
- DisableCopyDataPolicy: disableCopyDataPolicy,
- }
- }
if d.HasChange("data_source_query_policy") {
updateMasks = append(updateMasks, "data_source_query_policy")
dataSourceQueryPolicy, err := convertToDataSourceQueryPolicy(d)
@@ -511,6 +487,7 @@ func convertToQueryDataPolicy(d *schema.ResourceData) (*v1pb.QueryDataPolicy, er
raw := rawList[0].(map[string]interface{})
return &v1pb.QueryDataPolicy{
DisableExport: raw["disable_export"].(bool),
+ DisableCopyData: raw["disable_copy_data"].(bool),
MaximumResultSize: int64(raw["maximum_result_size"].(int)),
MaximumResultRows: int32(raw["maximum_result_rows"].(int)),
Timeout: &durationpb.Duration{
@@ -519,18 +496,6 @@ func convertToQueryDataPolicy(d *schema.ResourceData) (*v1pb.QueryDataPolicy, er
}, nil
}
-func convertToDisableCopyDataPolicy(d *schema.ResourceData) (*v1pb.DisableCopyDataPolicy, error) {
- rawList, ok := d.Get("disable_copy_data_policy").([]interface{})
- if !ok || len(rawList) != 1 {
- return nil, errors.Errorf("invalid disable_copy_data_policy")
- }
-
- raw := rawList[0].(map[string]interface{})
- return &v1pb.DisableCopyDataPolicy{
- Active: raw["enable"].(bool),
- }, nil
-}
-
func convertToDataSourceQueryPolicy(d *schema.ResourceData) (*v1pb.DataSourceQueryPolicy, error) {
rawList, ok := d.Get("data_source_query_policy").([]interface{})
if !ok || len(rawList) != 1 {
diff --git a/provider/resource_risk.go b/provider/resource_risk.go
index edd5526..923f92c 100644
--- a/provider/resource_risk.go
+++ b/provider/resource_risk.go
@@ -51,12 +51,14 @@ func resourceRisk() *schema.Resource {
Description: "The risk source. Check https://github.com/bytebase/bytebase/blob/main/proto/v1/v1/risk_service.proto#L138 for details",
},
"level": {
- Type: schema.TypeInt,
+ Type: schema.TypeString,
Required: true,
- ValidateFunc: validation.IntInSlice([]int{
- 300, 200, 100,
- }),
- Description: "The risk level, should be 300, 200 or 100. Higher number means higher level.",
+ ValidateFunc: validation.StringInSlice([]string{
+ v1pb.RiskLevel_HIGH.String(),
+ v1pb.RiskLevel_MODERATE.String(),
+ v1pb.RiskLevel_LOW.String(),
+ }, false),
+ Description: "The risk level. Check https://github.com/bytebase/bytebase/blob/fd87c6bfe8a0d4883f25eb480a3b05ed3c2e1727/proto/v1/v1/common.proto#L93 for details",
},
"active": {
Type: schema.TypeBool,
@@ -102,7 +104,7 @@ func setRisk(d *schema.ResourceData, risk *v1pb.Risk) diag.Diagnostics {
if err := d.Set("source", risk.Source.String()); err != nil {
return diag.Errorf("cannot set source for risk: %s", err.Error())
}
- if err := d.Set("level", int(risk.Level)); err != nil {
+ if err := d.Set("level", risk.Level.String()); err != nil {
return diag.Errorf("cannot set level for risk: %s", err.Error())
}
if err := d.Set("active", risk.Active); err != nil {
@@ -121,7 +123,7 @@ func resourceRiskCreate(ctx context.Context, d *schema.ResourceData, m interface
created, err := c.CreateRisk(ctx, &v1pb.Risk{
Title: d.Get("title").(string),
Active: d.Get("active").(bool),
- Level: int32(d.Get("level").(int)),
+ Level: v1pb.RiskLevel(v1pb.RiskLevel_value[d.Get("level").(string)]),
Source: v1pb.Risk_Source(v1pb.Risk_Source_value[d.Get("source").(string)]),
Condition: &expr.Expr{
Expression: d.Get("condition").(string),
@@ -156,7 +158,7 @@ func resourceRiskUpdate(ctx context.Context, d *schema.ResourceData, m interface
}
if d.HasChange("level") {
updateMasks = append(updateMasks, "level")
- existedRisk.Level = int32(d.Get("level").(int))
+ existedRisk.Level = v1pb.RiskLevel(v1pb.RiskLevel_value[d.Get("level").(string)])
}
if d.HasChange("source") {
updateMasks = append(updateMasks, "source")
diff --git a/provider/resource_risk_test.go b/provider/resource_risk_test.go
index 02dbe12..7f8c66d 100644
--- a/provider/resource_risk_test.go
+++ b/provider/resource_risk_test.go
@@ -22,8 +22,8 @@ func TestAccRisk(t *testing.T) {
title := "Test Risk"
titleUpdated := "Updated Test Risk"
source := v1pb.Risk_DDL.String()
- level := 300
- levelUpdated := 200
+ level := v1pb.RiskLevel_HIGH.String()
+ levelUpdated := v1pb.RiskLevel_MODERATE.String()
resource.Test(t, resource.TestCase{
PreCheck: func() {
@@ -39,7 +39,7 @@ func TestAccRisk(t *testing.T) {
internal.TestCheckResourceExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "title", title),
resource.TestCheckResourceAttr(resourceName, "source", source),
- resource.TestCheckResourceAttr(resourceName, "level", fmt.Sprintf("%d", level)),
+ resource.TestCheckResourceAttr(resourceName, "level", level),
resource.TestCheckResourceAttr(resourceName, "active", "true"),
resource.TestCheckResourceAttrSet(resourceName, "name"),
),
@@ -51,7 +51,7 @@ func TestAccRisk(t *testing.T) {
internal.TestCheckResourceExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "title", titleUpdated),
resource.TestCheckResourceAttr(resourceName, "source", source),
- resource.TestCheckResourceAttr(resourceName, "level", fmt.Sprintf("%d", levelUpdated)),
+ resource.TestCheckResourceAttr(resourceName, "level", levelUpdated),
resource.TestCheckResourceAttr(resourceName, "active", "false"),
),
},
@@ -62,7 +62,7 @@ func TestAccRisk(t *testing.T) {
internal.TestCheckResourceExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "title", titleUpdated),
resource.TestCheckResourceAttr(resourceName, "source", v1pb.Risk_DML.String()),
- resource.TestCheckResourceAttr(resourceName, "level", fmt.Sprintf("%d", level)),
+ resource.TestCheckResourceAttr(resourceName, "level", level),
resource.TestCheckResourceAttr(resourceName, "active", "true"),
),
},
@@ -92,7 +92,7 @@ func TestAccRisk_AllSources(t *testing.T) {
CheckDestroy: testAccCheckRiskDestroy,
Steps: []resource.TestStep{
{
- Config: testAccCheckRiskResource(identifier, fmt.Sprintf("Test Risk %s", source), source, 300, true),
+ Config: testAccCheckRiskResource(identifier, fmt.Sprintf("Test Risk %s", source), source, v1pb.RiskLevel_HIGH.String(), true),
Check: resource.ComposeTestCheckFunc(
internal.TestCheckResourceExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "source", source),
@@ -120,7 +120,7 @@ func TestAccRisk_InvalidInput(t *testing.T) {
resource "bytebase_risk" "%s" {
title = ""
source = "%s"
- level = 300
+ level = "HIGH"
active = true
condition = "{\"expressions\":[{\"title\":\"High risk database\",\"expression\":\"resource.database == 'production'\"}]}"
}
@@ -133,7 +133,7 @@ resource "bytebase_risk" "%s" {
resource "bytebase_risk" "%s" {
title = "Test Risk"
source = "INVALID_SOURCE"
- level = 300
+ level = "HIGH"
active = true
condition = "{\"expressions\":[{\"title\":\"High risk database\",\"expression\":\"resource.database == 'production'\"}]}"
}
@@ -146,7 +146,7 @@ resource "bytebase_risk" "%s" {
resource "bytebase_risk" "%s" {
title = "Test Risk"
source = "%s"
- level = 150
+ level = "RISK_LEVEL_UNSPECIFIED"
active = true
condition = "{\"expressions\":[{\"title\":\"High risk database\",\"expression\":\"resource.database == 'production'\"}]}"
}
@@ -157,7 +157,7 @@ resource "bytebase_risk" "%s" {
})
}
-func testAccCheckRiskResource(identifier, title, source string, level int, active bool) string {
+func testAccCheckRiskResource(identifier, title, source string, level string, active bool) string {
// Different conditions based on source type
condition := ""
switch source {
@@ -209,7 +209,7 @@ func testAccCheckRiskResource(identifier, title, source string, level int, activ
resource "bytebase_risk" "%s" {
title = "%s"
source = "%s"
- level = %d
+ level = "%s"
active = %t
condition = jsonencode(%s)
}
diff --git a/provider/resource_setting.go b/provider/resource_setting.go
index b21b932..82456fe 100644
--- a/provider/resource_setting.go
+++ b/provider/resource_setting.go
@@ -380,27 +380,16 @@ func convertToV1ApprovalSetting(d *schema.ResourceData) (*v1pb.WorkspaceApproval
},
}
- stepList, ok := rawFlow["steps"].([]interface{})
+ roleList, ok := rawFlow["roles"].([]interface{})
if !ok {
- return nil, errors.Errorf("invalid steps")
+ return nil, errors.Errorf("invalid roles")
}
-
- for _, step := range stepList {
- approvalStep := &v1pb.ApprovalStep{
- Type: v1pb.ApprovalStep_ANY,
- }
-
- rawStep := step.(map[string]interface{})
- role := rawStep["role"].(string)
- if !strings.HasPrefix(role, "roles/") {
- return nil, errors.Errorf("invalid role name: %v, role name should in roles/{role} format", role)
+ for _, raw := range roleList {
+ role := raw.(string)
+ if !strings.HasPrefix(role, internal.RoleNamePrefix) {
+ return nil, errors.Errorf("invalid role format, role must in roles/{id} format")
}
- approvalStep.Nodes = append(approvalStep.Nodes, &v1pb.ApprovalNode{
- Type: v1pb.ApprovalNode_ANY_IN_GROUP,
- Role: role,
- })
-
- approvalRule.Template.Flow.Steps = append(approvalRule.Template.Flow.Steps, approvalStep)
+ approvalRule.Template.Flow.Roles = append(approvalRule.Template.Flow.Roles, role)
}
workspaceApprovalSetting.Rules = append(workspaceApprovalSetting.Rules, approvalRule)
diff --git a/provider/resource_setting_test.go b/provider/resource_setting_test.go
index ec80506..042e254 100644
--- a/provider/resource_setting_test.go
+++ b/provider/resource_setting_test.go
@@ -31,7 +31,7 @@ func TestAccSetting_WorkspaceApproval(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.#", "1"),
resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.0.conditions.#", "1"),
resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.0.flow.#", "1"),
- resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.0.flow.0.steps.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.0.flow.0.roles.#", "2"),
),
},
// Update workspace approval setting
@@ -44,7 +44,7 @@ func TestAccSetting_WorkspaceApproval(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.#", "1"),
resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.0.conditions.#", "2"),
resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.0.flow.#", "1"),
- resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.0.flow.0.steps.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "approval_flow.0.rules.0.flow.0.roles.#", "1"),
),
},
},
@@ -228,9 +228,7 @@ resource "bytebase_setting" "%s" {
flow {
title = "Test"
description = "Test"
- steps {
- role = "roles/test"
- }
+ roles = ["roles/test"]
}
}
}
@@ -265,9 +263,7 @@ resource "bytebase_setting" "%s" {
flow {
title = "Test"
description = "Test"
- steps {
- role = "invalid-role"
- }
+ roles = ["invalid-role"]
}
}
}
@@ -339,12 +335,10 @@ resource "bytebase_setting" "%s" {
flow {
title = "DDL Approval Flow"
description = "Approval flow for DDL operations"
- steps {
- role = bytebase_role.approval_role_%s.name
- }
- steps {
- role = bytebase_role.approval_role_%s.name
- }
+ roles = [
+ bytebase_role.approval_role_%s.name,
+ bytebase_role.approval_role_%s.name
+ ]
}
}
}
@@ -377,9 +371,7 @@ resource "bytebase_setting" "%s" {
flow {
title = "Updated Approval Flow"
description = "Updated approval flow"
- steps {
- role = bytebase_role.approval_role_%s.name
- }
+ roles = [bytebase_role.approval_role_%s.name]
}
}
}
diff --git a/tutorials/0-provider.tf b/tutorials/0-provider.tf
index 0e98f00..4ab62b9 100644
--- a/tutorials/0-provider.tf
+++ b/tutorials/0-provider.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "3.10.0"
+ version = "3.11.1"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/tutorials/1-3-env-policy-data.tf b/tutorials/1-3-env-policy-data.tf
index e965794..6faf3c3 100644
--- a/tutorials/1-3-env-policy-data.tf
+++ b/tutorials/1-3-env-policy-data.tf
@@ -1,10 +1,10 @@
-resource "bytebase_policy" "disable_copy_data_policy_prod" {
+resource "bytebase_policy" "disable_copy_data_prod" {
depends_on = [bytebase_setting.environments]
parent = bytebase_setting.environments.environment_setting[0].environment[1].name
- type = "DISABLE_COPY_DATA"
+ type = "DATA_QUERY"
- disable_copy_data_policy {
- enable = true
+ query_data_policy {
+ disable_copy_data = true
}
}
@@ -18,4 +18,4 @@ resource "bytebase_policy" "data_source_query_policy_prod" {
disallow_ddl = true
disallow_dml = true
}
-}
\ No newline at end of file
+}
diff --git a/tutorials/4-2-risk.tf b/tutorials/4-2-risk.tf
index 4506445..b5dadbb 100644
--- a/tutorials/4-2-risk.tf
+++ b/tutorials/4-2-risk.tf
@@ -1,7 +1,7 @@
resource "bytebase_risk" "dml_moderate" {
title = "DML Moderate Risk"
source = "DML"
- level = 200
+ level = "MODERATE"
active = true
condition = "resource.environment_id == \"prod\" && statement.affected_rows >= 100"
}
@@ -9,7 +9,7 @@ resource "bytebase_risk" "dml_moderate" {
resource "bytebase_risk" "ddl_high" {
title = "DDL High Risk"
source = "DDL"
- level = 300
+ level = "HIGH"
active = true
condition = "resource.environment_id == \"prod\""
-}
\ No newline at end of file
+}
diff --git a/tutorials/4-3-approval-flow.tf b/tutorials/4-3-approval-flow.tf
index 8af617f..d6bed80 100644
--- a/tutorials/4-3-approval-flow.tf
+++ b/tutorials/4-3-approval-flow.tf
@@ -6,10 +6,11 @@ resource "bytebase_setting" "approval_flow" {
flow {
title = "Project Owner → DBA → Admin"
description = "Need DBA and workspace admin approval"
-
- steps { role = "roles/projectOwner" }
- steps { role = "roles/workspaceDBA" }
- steps { role = "roles/workspaceAdmin" }
+ roles = [
+ "roles/projectOwner",
+ "roles/workspaceDBA",
+ "roles/workspaceAdmin"
+ ]
}
conditions {
source = "DML"
@@ -21,4 +22,4 @@ resource "bytebase_setting" "approval_flow" {
}
}
}
-}
\ No newline at end of file
+}