diff --git a/VERSION b/VERSION
index ece61c6..f9cbc01 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.6
\ No newline at end of file
+1.0.7
\ No newline at end of file
diff --git a/api/setting.go b/api/setting.go
index 09b82cb..fab775f 100644
--- a/api/setting.go
+++ b/api/setting.go
@@ -6,6 +6,8 @@ type SettingName string
const (
// SettingWorkspaceApproval is the setting name for workspace approval config.
SettingWorkspaceApproval SettingName = "bb.workspace.approval"
+ // SettingWorkspaceProfile is the setting name for workspace profile settings.
+ SettingWorkspaceProfile SettingName = "bb.workspace.profile"
// SettingWorkspaceExternalApproval is the setting name for workspace external approval config.
SettingWorkspaceExternalApproval SettingName = "bb.workspace.approval.external"
)
diff --git a/docs/data-sources/setting.md b/docs/data-sources/setting.md
index 1ce3d3d..bcf5780 100644
--- a/docs/data-sources/setting.md
+++ b/docs/data-sources/setting.md
@@ -19,12 +19,28 @@ The setting data source.
- `name` (String)
+### Optional
+
+- `workspace_profile` (Block List, Max: 1) (see [below for nested schema](#nestedblock--workspace_profile))
+
### Read-Only
- `approval_flow` (Block List) Configure risk level and approval flow for different tasks. Require ENTERPRISE subscription. (see [below for nested schema](#nestedblock--approval_flow))
- `external_approval_nodes` (Block List) Configure external nodes in the approval flow. Require ENTERPRISE subscription. (see [below for nested schema](#nestedblock--external_approval_nodes))
- `id` (String) The ID of this resource.
+
+### Nested Schema for `workspace_profile`
+
+Optional:
+
+- `disallow_password_signin` (Boolean) Whether to disallow password signin. (Except workspace admins). Require ENTERPRISE subscription
+- `disallow_signup` (Boolean) Disallow self-service signup, users can only be invited by the owner. Require PRO subscription.
+- `domains` (List of String) The workspace domain, e.g. bytebase.com. Required for the group
+- `enforce_identity_domain` (Boolean) Only user and group from the domains can be created and login.
+- `external_url` (String) The URL user visits Bytebase. The external URL is used for: 1. Constructing the correct callback URL when configuring the VCS provider. The callback URL points to the frontend; 2. Creating the correct webhook endpoint when configuring the project GitOps workflow. The webhook endpoint points to the backend.
+
+
### Nested Schema for `approval_flow`
diff --git a/docs/resources/setting.md b/docs/resources/setting.md
index 4912e6f..2e1b80e 100644
--- a/docs/resources/setting.md
+++ b/docs/resources/setting.md
@@ -23,6 +23,7 @@ The setting resource.
- `approval_flow` (Block List) Configure risk level and approval flow for different tasks. Require ENTERPRISE subscription. (see [below for nested schema](#nestedblock--approval_flow))
- `external_approval_nodes` (Block List) Configure external nodes in the approval flow. Require ENTERPRISE subscription. (see [below for nested schema](#nestedblock--external_approval_nodes))
+- `workspace_profile` (Block List, Max: 1) (see [below for nested schema](#nestedblock--workspace_profile))
### Read-Only
@@ -100,3 +101,16 @@ Required:
- `title` (String) The external node title.
+
+
+### Nested Schema for `workspace_profile`
+
+Optional:
+
+- `disallow_password_signin` (Boolean) Whether to disallow password signin. (Except workspace admins). Require ENTERPRISE subscription
+- `disallow_signup` (Boolean) Disallow self-service signup, users can only be invited by the owner. Require PRO subscription.
+- `domains` (List of String) The workspace domain, e.g. bytebase.com. Required for the group
+- `enforce_identity_domain` (Boolean) Only user and group from the domains can be created and login.
+- `external_url` (String) The URL user visits Bytebase. The external URL is used for: 1. Constructing the correct callback URL when configuring the VCS provider. The callback URL points to the frontend; 2. Creating the correct webhook endpoint when configuring the project GitOps workflow. The webhook endpoint points to the backend.
+
+
diff --git a/examples/settings/main.tf b/examples/settings/main.tf
index 8dc2b66..4c9244f 100644
--- a/examples/settings/main.tf
+++ b/examples/settings/main.tf
@@ -25,6 +25,10 @@ data "bytebase_setting" "external_approval" {
name = "bb.workspace.approval.external"
}
+data "bytebase_setting" "workspace_profile" {
+ name = "bb.workspace.profile"
+}
+
output "approval_flow" {
value = data.bytebase_setting.approval_flow
}
@@ -32,3 +36,7 @@ output "approval_flow" {
output "external_approval" {
value = data.bytebase_setting.external_approval
}
+
+output "workspace_profile" {
+ value = data.bytebase_setting.workspace_profile
+}
diff --git a/examples/setup/gitops.tf b/examples/setup/gitops.tf
index a30fa6a..1b91dc1 100644
--- a/examples/setup/gitops.tf
+++ b/examples/setup/gitops.tf
@@ -10,7 +10,9 @@ resource "bytebase_vcs_provider" "github" {
resource "bytebase_vcs_connector" "github" {
depends_on = [
bytebase_project.sample_project,
- bytebase_vcs_provider.github
+ bytebase_vcs_provider.github,
+ # vcs connector requires the external_url.
+ bytebase_setting.workspace_profile
]
resource_id = "connector-github"
diff --git a/examples/setup/main.tf b/examples/setup/main.tf
index 580fef4..d6c3f96 100644
--- a/examples/setup/main.tf
+++ b/examples/setup/main.tf
@@ -25,3 +25,12 @@ locals {
instance_id_prod = "prod-sample-instance"
project_id = "project-sample"
}
+
+resource "bytebase_setting" "workspace_profile" {
+ name = "bb.workspace.profile"
+
+ workspace_profile {
+ external_url = "https://bytebase.example.com"
+ domains = ["bytebase.com"]
+ }
+}
diff --git a/examples/setup/users.tf b/examples/setup/users.tf
index 99c6136..5a6c3ef 100644
--- a/examples/setup/users.tf
+++ b/examples/setup/users.tf
@@ -20,7 +20,9 @@ resource "bytebase_user" "project_developer" {
resource "bytebase_group" "developers" {
depends_on = [
bytebase_user.workspace_dba,
- bytebase_user.project_developer
+ bytebase_user.project_developer,
+ # group requires the domain.
+ bytebase_setting.workspace_profile
]
email = "developers@bytebase.com"
diff --git a/provider/data_source_setting.go b/provider/data_source_setting.go
index 5b5c6f7..239a169 100644
--- a/provider/data_source_setting.go
+++ b/provider/data_source_setting.go
@@ -28,10 +28,60 @@ func dataSourceSetting() *schema.Resource {
ValidateFunc: validation.StringInSlice([]string{
string(api.SettingWorkspaceApproval),
string(api.SettingWorkspaceExternalApproval),
+ string(api.SettingWorkspaceProfile),
}, false),
},
"approval_flow": getWorkspaceApprovalSetting(true),
"external_approval_nodes": getExternalApprovalSetting(true),
+ "workspace_profile": getWorkspaceProfileSetting(true),
+ },
+ }
+}
+
+func getWorkspaceProfileSetting(computed bool) *schema.Schema {
+ return &schema.Schema{
+ Computed: computed,
+ Optional: true,
+ Default: nil,
+ Type: schema.TypeList,
+ MaxItems: 1,
+ MinItems: 1,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "external_url": {
+ Type: schema.TypeString,
+ Computed: computed,
+ Optional: true,
+ Description: "The URL user visits Bytebase. The external URL is used for: 1. Constructing the correct callback URL when configuring the VCS provider. The callback URL points to the frontend; 2. Creating the correct webhook endpoint when configuring the project GitOps workflow. The webhook endpoint points to the backend.",
+ },
+ "disallow_signup": {
+ Type: schema.TypeBool,
+ Computed: computed,
+ Optional: true,
+ Description: "Disallow self-service signup, users can only be invited by the owner. Require PRO subscription.",
+ },
+ "disallow_password_signin": {
+ Type: schema.TypeBool,
+ Computed: computed,
+ Optional: true,
+ Description: "Whether to disallow password signin. (Except workspace admins). Require ENTERPRISE subscription",
+ },
+ "domains": {
+ Type: schema.TypeList,
+ Computed: computed,
+ Optional: true,
+ Description: "The workspace domain, e.g. bytebase.com. Required for the group",
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ },
+ "enforce_identity_domain": {
+ Type: schema.TypeBool,
+ Computed: computed,
+ Optional: true,
+ Description: "Only user and group from the domains can be created and login.",
+ },
+ },
},
}
}
@@ -215,6 +265,12 @@ func setSettingMessage(ctx context.Context, d *schema.ResourceData, client api.C
return diag.Errorf("cannot set external_approval_nodes: %s", err.Error())
}
}
+ if value := setting.Value.GetWorkspaceProfileSettingValue(); value != nil {
+ settingVal := flattenWorkspaceProfileSetting(value)
+ if err := d.Set("workspace_profile", settingVal); err != nil {
+ return diag.Errorf("cannot set workspace_profile: %s", err.Error())
+ }
+ }
return nil
}
@@ -354,3 +410,15 @@ func flattenExternalApprovalSetting(setting *v1pb.ExternalApprovalSetting) []int
}
return []interface{}{approvalSetting}
}
+
+func flattenWorkspaceProfileSetting(setting *v1pb.WorkspaceProfileSetting) []interface{} {
+ raw := map[string]interface{}{}
+
+ raw["external_url"] = setting.ExternalUrl
+ raw["disallow_signup"] = setting.DisallowSignup
+ raw["disallow_password_signin"] = setting.DisallowPasswordSignin
+ raw["enforce_identity_domain"] = setting.EnforceIdentityDomain
+ raw["domains"] = setting.Domains
+
+ return []interface{}{raw}
+}
diff --git a/provider/resource_setting.go b/provider/resource_setting.go
index 7fd5ffa..1dfc4d5 100644
--- a/provider/resource_setting.go
+++ b/provider/resource_setting.go
@@ -34,10 +34,12 @@ func resourceSetting() *schema.Resource {
ValidateFunc: validation.StringInSlice([]string{
string(api.SettingWorkspaceApproval),
string(api.SettingWorkspaceExternalApproval),
+ string(api.SettingWorkspaceProfile),
}, false),
},
"approval_flow": getWorkspaceApprovalSetting(false),
"external_approval_nodes": getExternalApprovalSetting(false),
+ "workspace_profile": getWorkspaceProfileSetting(false),
},
}
}
@@ -52,6 +54,7 @@ func resourceSettingUpsert(ctx context.Context, d *schema.ResourceData, m interf
setting := &v1pb.Setting{
Name: settingName,
}
+ updateMasks := []string{}
switch name {
case api.SettingWorkspaceApproval:
@@ -74,11 +77,22 @@ func resourceSettingUpsert(ctx context.Context, d *schema.ResourceData, m interf
ExternalApprovalSettingValue: externalApproval,
},
}
+ case api.SettingWorkspaceProfile:
+ workspaceProfile, updatePathes, err := convertToV1WorkspaceProfileSetting(d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ setting.Value = &v1pb.Value{
+ Value: &v1pb.Value_WorkspaceProfileSettingValue{
+ WorkspaceProfileSettingValue: workspaceProfile,
+ },
+ }
+ updateMasks = updatePathes
default:
return diag.FromErr(errors.Errorf("Unsupport setting: %v", name))
}
- updatedSetting, err := c.UpsertSetting(ctx, setting, []string{})
+ updatedSetting, err := c.UpsertSetting(ctx, setting, updateMasks)
if err != nil {
return diag.FromErr(err)
}
@@ -93,6 +107,45 @@ func resourceSettingUpsert(ctx context.Context, d *schema.ResourceData, m interf
return diags
}
+func convertToV1WorkspaceProfileSetting(d *schema.ResourceData) (*v1pb.WorkspaceProfileSetting, []string, error) {
+ rawList, ok := d.Get("workspace_profile").([]interface{})
+ if !ok || len(rawList) != 1 {
+ return nil, nil, errors.Errorf("invalid workspace_profile")
+ }
+
+ updateMasks := []string{}
+ raw := rawList[0].(map[string]interface{})
+
+ workspacePrfile := &v1pb.WorkspaceProfileSetting{}
+
+ if externalURL, ok := raw["external_url"]; ok {
+ workspacePrfile.ExternalUrl = externalURL.(string)
+ updateMasks = append(updateMasks, "value.workspace_profile_setting_value.external_url")
+ }
+ if disallowSignup, ok := raw["disallow_signup"]; ok {
+ workspacePrfile.DisallowSignup = disallowSignup.(bool)
+ updateMasks = append(updateMasks, "value.workspace_profile_setting_value.disallow_signup")
+ }
+ if disallowPasswordSignin, ok := raw["disallow_password_signin"]; ok {
+ workspacePrfile.DisallowPasswordSignin = disallowPasswordSignin.(bool)
+ updateMasks = append(updateMasks, "value.workspace_profile_setting_value.disallow_password_signin")
+ }
+ if domains, ok := raw["domains"]; ok {
+ if enforceIdentityDomain, ok := raw["enforce_identity_domain"]; ok {
+ workspacePrfile.EnforceIdentityDomain = enforceIdentityDomain.(bool)
+ updateMasks = append(updateMasks, "value.workspace_profile_setting_value.enforce_identity_domain")
+ }
+ for _, domain := range domains.([]interface{}) {
+ workspacePrfile.Domains = append(workspacePrfile.Domains, domain.(string))
+ }
+ updateMasks = append(updateMasks, "value.workspace_profile_setting_value.domains")
+ } else if _, ok := raw["enforce_identity_domain"]; ok {
+ return nil, nil, errors.Errorf("enforce_identity_domain must works with domains")
+ }
+
+ return workspacePrfile, updateMasks, nil
+}
+
func convertToV1ExternalNodesSetting(d *schema.ResourceData) (*v1pb.ExternalApprovalSetting, error) {
rawList, ok := d.Get("external_approval_nodes").([]interface{})
if !ok || len(rawList) != 1 {