From e4f848e827516bc0d22a509cfe4593414d955130 Mon Sep 17 00:00:00 2001 From: Amanda Hager Lopes de Andrade Katz Date: Tue, 17 Dec 2024 15:13:53 -0300 Subject: [PATCH] fix: validate admin user --- internal/provider/resource_access_offer.go | 19 ++++++-- .../provider/resource_access_offer_test.go | 46 +++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/internal/provider/resource_access_offer.go b/internal/provider/resource_access_offer.go index 5e99cfcf..7d01f515 100644 --- a/internal/provider/resource_access_offer.go +++ b/internal/provider/resource_access_offer.go @@ -153,9 +153,9 @@ func (a *accessOfferResource) Create(ctx context.Context, req resource.CreateReq } } - // validate if there are overlaps + // validate if there are overlaps or admin user // validation is done here considering dynamic (juju_user resource) and static values for users - err := validateNoOverlaps(adminUsers, consumeUsers, readUsers) + err := validateNoOverlapsNoAdmin(adminUsers, consumeUsers, readUsers) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create access offer resource, got error: %s", err)) return @@ -307,9 +307,9 @@ func (a *accessOfferResource) Update(ctx context.Context, req resource.UpdateReq } } - // validate if there are overlaps + // validate if there are overlaps or admin user // validation is done here considering dynamic (juju_user resource) and static values for users - err := validateNoOverlaps(adminUsers, consumeUsers, readUsers) + err := validateNoOverlapsNoAdmin(adminUsers, consumeUsers, readUsers) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create access offer resource, got error: %s", err)) return @@ -509,18 +509,27 @@ func (a *accessOfferResource) trace(msg string, additionalFields ...map[string]i } // Helpers -func validateNoOverlaps(admin, consume, read []string) error { +func validateNoOverlapsNoAdmin(admin, consume, read []string) error { sets := map[string]struct{}{} for _, v := range consume { + if v == "admin" { + return fmt.Errorf("user admin is not allowed") + } sets[v] = struct{}{} } for _, v := range read { + if v == "admin" { + return fmt.Errorf("user admin is not allowed") + } if _, exists := sets[v]; exists { return fmt.Errorf("user '%s' appears in both 'consume' and 'read'", v) } sets[v] = struct{}{} } for _, v := range admin { + if v == "admin" { + return fmt.Errorf("user admin is not allowed") + } if _, exists := sets[v]; exists { return fmt.Errorf("user '%s' appears in multiple roles (e.g., 'consume', 'read', 'admin')", v) } diff --git a/internal/provider/resource_access_offer_test.go b/internal/provider/resource_access_offer_test.go index e0665209..b95bdb9b 100644 --- a/internal/provider/resource_access_offer_test.go +++ b/internal/provider/resource_access_offer_test.go @@ -84,6 +84,23 @@ func TestAcc_ResourceAccessOffer_ErrorWhenUsedWithJAAS(t *testing.T) { }) } +func TestAcc_ResourceAccessOffer_ErrorWhenUsedWithAdmin(t *testing.T) { + SkipJAAS(t) + + modelNameAdminTest := acctest.RandomWithPrefix("tf-access-admin-model") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: frameworkProviderFactories, + Steps: []resource.TestStep{ + { // Test username admin validation + Config: testAccResourceAccessOfferAdminUser(modelNameAdminTest), + ExpectError: regexp.MustCompile("user admin is not allowed.*"), + }, + }, + }) +} + func testAccResourceAccessOfferFixedUser() string { return ` resource "juju_access_offer" "test" { @@ -92,6 +109,35 @@ resource "juju_access_offer" "test" { }` } +func testAccResourceAccessOfferAdminUser(modelName string) string { + return internaltesting.GetStringFromTemplateWithData("testAccResourceAccessOfferAdminUser", ` +resource "juju_model" "{{.ModelName}}" { +name = "{{.ModelName}}" +} + +resource "juju_application" "appone" { + name = "appone" + model = juju_model.{{.ModelName}}.name + + charm { + name = "juju-qa-dummy-source" + base = "ubuntu@22.04" + } +} + +resource "juju_offer" "appone_endpoint" { + model = juju_model.{{.ModelName}}.name + application_name = juju_application.appone.name + endpoint = "sink" +} + +resource "juju_access_offer" "test" { + offer_url = juju_offer.appone_endpoint.url + admin = ["admin"] +}`, internaltesting.TemplateData{ + "ModelName": modelName}) +} + func testAccResourceAccessOffer(AdminUserName, ConsumeUserName, ReadUserName, OfferAdmin, OfferConsume, OfferRead, userPassword, modelName string) string { return internaltesting.GetStringFromTemplateWithData( "testAccResourceAccessOffer",