From 8fae0d3a42b7fe0e1142140669db7a023315e8be Mon Sep 17 00:00:00 2001 From: Brett Kochendorfer Date: Wed, 2 Apr 2025 14:46:53 -0500 Subject: [PATCH] feat(sigsci_corp_user): Add corp user resource This resource allows the provider to create, read, and delete a SigSci Corp User. It also allows managing membership to sites and level of access on initial creation. The upstream library (sigsci-go) does not seem to support membership updates on a user. I would love to get some feedback on how we should handle membership either here or in the upstream module. --- examples/resources/sigsci_corp_user/import.sh | 1 + .../resources/sigsci_corp_user/resource.tf | 12 ++ provider/provider.go | 1 + provider/resource_corp_user.go | 129 ++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 examples/resources/sigsci_corp_user/import.sh create mode 100644 examples/resources/sigsci_corp_user/resource.tf create mode 100644 provider/resource_corp_user.go diff --git a/examples/resources/sigsci_corp_user/import.sh b/examples/resources/sigsci_corp_user/import.sh new file mode 100644 index 0000000..bb0361b --- /dev/null +++ b/examples/resources/sigsci_corp_user/import.sh @@ -0,0 +1 @@ +terraform import sigsci_corp_user.test id diff --git a/examples/resources/sigsci_corp_user/resource.tf b/examples/resources/sigsci_corp_user/resource.tf new file mode 100644 index 0000000..77067b0 --- /dev/null +++ b/examples/resources/sigsci_corp_user/resource.tf @@ -0,0 +1,12 @@ +resource "sigsci_corp_user" "test" { + email = "test-user@fastly.com" + role = "user" + + memberships = [ + { + site_name = "test-test", + role = "user" + }, + ] +} + diff --git a/provider/provider.go b/provider/provider.go index 37529af..6c2615d 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -80,6 +80,7 @@ func Provider() terraform.ResourceProvider { "sigsci_corp_integration": resourceCorpIntegration(), "sigsci_corp_cloudwaf_instance": resourceCorpCloudWAFInstance(), "sigsci_corp_cloudwaf_certificate": resourceCorpCloudWAFCertificate(), + "sigsci_corp_user": resourceCorpUser(), "sigsci_edge_deployment": resourceEdgeDeployment(), "sigsci_edge_deployment_service": resourceEdgeDeploymentService(), "sigsci_edge_deployment_service_backend": resourceEdgeDeploymentServiceBackend(), diff --git a/provider/resource_corp_user.go b/provider/resource_corp_user.go new file mode 100644 index 0000000..3385acc --- /dev/null +++ b/provider/resource_corp_user.go @@ -0,0 +1,129 @@ +package provider + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/signalsciences/go-sigsci" +) + +func resourceCorpUser() *schema.Resource { + return &schema.Resource{ + Create: resourceCorpUserCreate, + Read: resourceCorpUserRead, + Update: resourceCorpUserUpdate, + Delete: resourceCorpUserDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "email": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "role": { + Type: schema.TypeString, + Optional: true, + Default: "user", + }, + "memberships": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "site_name": { + Type: schema.TypeString, + Required: true, + }, + "role": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + } +} + +func resourceCorpUserCreate(d *schema.ResourceData, m interface{}) error { + pm := m.(providerMetadata) + client := pm.Client + corp := pm.Corp + + email := d.Get("email").(string) + role := d.Get("role").(string) + + // Build site memberships + rawMemberships := d.Get("memberships").([]interface{}) + var memberships []sigsci.SiteMembership + for _, m := range rawMemberships { + mem := m.(map[string]interface{}) + memberships = append(memberships, sigsci.NewSiteMembership( + mem["site_name"].(string), + sigsci.Role(mem["role"].(string)), + )) + } + + invite := sigsci.NewCorpUserInvite(sigsci.Role(role), memberships) + + if _, err := client.InviteUser(corp, email, invite); err != nil { + return fmt.Errorf("error inviting corp user: %w", err) + } + + d.SetId(email) + return resourceCorpUserRead(d, m) +} + +func resourceCorpUserRead(d *schema.ResourceData, m interface{}) error { + pm := m.(providerMetadata) + client := pm.Client + corp := pm.Corp + + email := d.Id() + user, err := client.GetCorpUser(corp, email) + if err != nil { + d.SetId("") + fmt.Println(err) + return nil + } + + d.Set("email", user.Email) + d.Set("role", user.Role) + + // Flatten memberships + var memberships []map[string]interface{} + for siteName, role := range user.Memberships { + memberships = append(memberships, map[string]interface{}{ + "site_name": siteName, + "role": role, + }) + } + d.Set("memberships", memberships) + + return nil +} + +func resourceCorpUserUpdate(d *schema.ResourceData, m interface{}) error { + // The Signal Sciences API does not support updating user roles or memberships directly. + // To change a user's role or memberships, they must be removed and re-invited with the new settings. + return fmt.Errorf("updating corp users is not supported by the Signal Sciences API") +} + +func resourceCorpUserDelete(d *schema.ResourceData, m interface{}) error { + pm := m.(providerMetadata) + client := pm.Client + corp := pm.Corp + + email := d.Id() + + if err := client.DeleteCorpUser(corp, email); err != nil { + return fmt.Errorf("error deleting corp user: %w", err) + } + + d.SetId("") + return nil +}