diff --git a/docs/resources/secrets_sync_supabase.md b/docs/resources/secrets_sync_supabase.md new file mode 100644 index 0000000..27160bc --- /dev/null +++ b/docs/resources/secrets_sync_supabase.md @@ -0,0 +1,42 @@ +--- +page_title: "doppler_secrets_sync_supabase Resource - terraform-provider-doppler" +subcategory: "Integrations" +description: |- + Manage a Supabase Doppler sync. +--- + +# doppler_secrets_sync_supabase (Resource) + +Manage a Supabase Doppler sync. + +## Example Usage + +```terraform +resource "doppler_secrets_sync_supabase" "backend_prod" { + integration = "bae40485-eca7-478b-abd8-34100c82c679" + project = "backend" + config = "prd" + + project_id = "abcdefghijklmnopqrst" + + delete_behavior = "leave_in_target" +} +``` + + +## Schema + +### Required + +- `config` (String) The name of the Doppler config +- `integration` (String) The slug of the integration to use for this sync +- `project` (String) The name of the Doppler project +- `project_id` (String) The Supabase project reference ID + +### Optional + +- `delete_behavior` (String) The behavior to be performed on the secrets in the sync target when this resource is deleted or recreated. Either `leave_in_target` (default) or `delete_from_target`. + +### Read-Only + +- `id` (String) The ID of this resource. diff --git a/docs/resources/secrets_sync_vercel.md b/docs/resources/secrets_sync_vercel.md new file mode 100644 index 0000000..ed07bbe --- /dev/null +++ b/docs/resources/secrets_sync_vercel.md @@ -0,0 +1,59 @@ +--- +page_title: "doppler_secrets_sync_vercel Resource - terraform-provider-doppler" +subcategory: "Integrations" +description: |- + Manage a Vercel Doppler sync. +--- + +# doppler_secrets_sync_vercel (Resource) + +Manage a Vercel Doppler sync. + +## Example Usage + +```terraform +resource "doppler_secrets_sync_vercel" "backend_prod" { + integration = "bae40485-eca7-478b-abd8-34100c82c679" + project = "backend" + config = "prd" + + team_id = "team_xxxxxxxxxx" + project_id = "prj_xxxxxxxxxx" + target_id = "production" + variable_type = "sensitive" + + delete_behavior = "leave_in_target" +} + +resource "doppler_secrets_sync_vercel" "backend_stg" { + integration = "bae40485-eca7-478b-abd8-34100c82c679" + project = "backend" + config = "stg" + + project_id = "prj_xxxxxxxxxx" + target_id = "preview" + + delete_behavior = "leave_in_target" +} +``` + + +## Schema + +### Required + +- `config` (String) The name of the Doppler config +- `integration` (String) The slug of the integration to use for this sync +- `project` (String) The name of the Doppler project +- `project_id` (String) The Vercel project ID +- `target_id` (String) The Vercel environment target ("production", "preview", "development", or a custom environment ID) + +### Optional + +- `delete_behavior` (String) The behavior to be performed on the secrets in the sync target when this resource is deleted or recreated. Either `leave_in_target` (default) or `delete_from_target`. +- `team_id` (String) The Vercel team ID. Required for team-scoped projects, omit for personal account projects. +- `variable_type` (String) The type of Vercel environment variable ("encrypted", "sensitive", "plain"). Defaults to "encrypted" if omitted. + +### Read-Only + +- `id` (String) The ID of this resource. diff --git a/doppler/models.go b/doppler/models.go index 2416255..d90780d 100644 --- a/doppler/models.go +++ b/doppler/models.go @@ -129,10 +129,11 @@ type IntegrationResponse struct { type SyncData = map[string]interface{} type Sync struct { - Slug string `json:"slug"` - Project string `json:"project"` - Config string `json:"config"` - Integration string `json:"integration"` + Slug string `json:"slug"` + Project string `json:"project"` + Config string `json:"config"` + Integration string `json:"integration"` + Data map[string]interface{} `json:"data"` } type SyncResponse struct { diff --git a/doppler/provider.go b/doppler/provider.go index 941bed1..5072d8a 100644 --- a/doppler/provider.go +++ b/doppler/provider.go @@ -112,6 +112,14 @@ func Provider() *schema.Provider { "doppler_integration_gcp_secret_manager": resourceIntegrationGCPSecretManager(), "doppler_secrets_sync_gcp_secret_manager": resourceSyncGCPSecretManager(), + + // creating Vercel oauth integrations is not currently supported + // "doppler_integration_vercel": resourceIntegrationVercel(), + "doppler_secrets_sync_vercel": resourceSyncVercel(), + + // creating Supabase oauth integrations is not currently supported + // "doppler_integration_supabase": resourceIntegrationSupabase(), + "doppler_secrets_sync_supabase": resourceSyncSupabase(), }, DataSourcesMap: map[string]*schema.Resource{ "doppler_secrets": dataSourceSecrets(), diff --git a/doppler/resource_sync.go b/doppler/resource_sync.go index be1809e..06c3dff 100644 --- a/doppler/resource_sync.go +++ b/doppler/resource_sync.go @@ -9,10 +9,12 @@ import ( ) type SyncDataBuilderFunc = func(d *schema.ResourceData) SyncData +type SyncDataReaderFunc = func(data map[string]interface{}, d *schema.ResourceData) error type ResourceSyncBuilder struct { DataSchema map[string]*schema.Schema DataBuilder IntegrationDataBuilderFunc + DataReader SyncDataReaderFunc CustomizeDiff schema.CustomizeDiffFunc } @@ -109,6 +111,12 @@ func (builder ResourceSyncBuilder) ReadContextFunc() schema.ReadContextFunc { return diag.FromErr(err) } + if builder.DataReader != nil && sync.Data != nil { + if err = builder.DataReader(sync.Data, d); err != nil { + return diag.FromErr(err) + } + } + return diags } } diff --git a/doppler/resource_sync_types.go b/doppler/resource_sync_types.go index beee208..33a2186 100644 --- a/doppler/resource_sync_types.go +++ b/doppler/resource_sync_types.go @@ -572,6 +572,98 @@ func resourceSyncAzureVault() *schema.Resource { return builder.Build() } +func resourceSyncVercel() *schema.Resource { + builder := ResourceSyncBuilder{ + DataSchema: map[string]*schema.Schema{ + "team_id": { + Description: "The Vercel team ID", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "project_id": { + Description: "The Vercel project ID", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "target_id": { + Description: "The Vercel environment target (\"production\", \"preview\", \"development\", or a custom environment ID)", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "variable_type": { + Description: "The type of Vercel environment variable (\"encrypted\", \"sensitive\", \"plain\")", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"encrypted", "sensitive", "plain"}, false), + DiffSuppressFunc: func(k, oldValue, newValue string, d *schema.ResourceData) bool { + if oldValue == "" && newValue == "encrypted" { + return true + } else if oldValue == "encrypted" && newValue == "" { + return true + } else { + return newValue == oldValue + } + }, + }, + }, + DataBuilder: func(d *schema.ResourceData) IntegrationData { + payload := map[string]interface{}{ + "project_id": d.Get("project_id"), + "target_id": d.Get("target_id"), + } + if teamID, ok := d.GetOk("team_id"); ok { + payload["team_id"] = teamID + } + if variableType, ok := d.GetOk("variable_type"); ok { + payload["variable_type"] = variableType + } + return payload + }, + DataReader: func(data map[string]interface{}, d *schema.ResourceData) error { + for _, key := range []string{"team_id", "project_id", "target_id", "variable_type"} { + if v, ok := data[key]; ok { + if err := d.Set(key, v); err != nil { + return err + } + } + } + return nil + }, + } + return builder.Build() +} + +func resourceSyncSupabase() *schema.Resource { + builder := ResourceSyncBuilder{ + DataSchema: map[string]*schema.Schema{ + "project_id": { + Description: "The Supabase project reference ID", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + DataBuilder: func(d *schema.ResourceData) IntegrationData { + return map[string]interface{}{ + "project_id": d.Get("project_id"), + } + }, + DataReader: func(data map[string]interface{}, d *schema.ResourceData) error { + if v, ok := data["project_id"]; ok { + if err := d.Set("project_id", v); err != nil { + return err + } + } + return nil + }, + } + return builder.Build() +} + func resourceSyncGCPSecretManager() *schema.Resource { name_regex, _ := regexp.Compile("^[a-zA-Z0-9_-]*$") builder := ResourceSyncBuilder{