//go:build integration // admin_integration_test.go provides integration tests for admin user management operations. // These tests require real AWS Cognito and Permit.io credentials and are not run in CI/CD. // Run with: go test -tags=integration ./test/integration/... package integration import ( "context" "fmt" "net/http" "os" "path/filepath" "strings" "testing" "time" "github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider" "github.com/google/uuid" "github.com/joho/godotenv" "github.com/stretchr/testify/suite" "queryorchestration/internal/serviceconfig/aws" "queryorchestration/internal/usermanagement" ) // AdminIntegrationTestSuite provides integration testing for admin user management operations // using real AWS Cognito and Permit.io services. type AdminIntegrationTestSuite struct { suite.Suite cognitoClient *cognitoidentityprovider.Client cognitoConfig *usermanagement.CognitoConfig httpClient *http.Client permitConfig *usermanagement.PermitConfig testUsers []string // Track users for cleanup (emails) permitOnlyUsers map[string]string // Track Permit.io-only users: email -> SubjectID } // SetupSuite runs once before all tests to initialize clients and validate configuration. func (s *AdminIntegrationTestSuite) SetupSuite() { // Load .env file if it exists (supports running tests from project root or test/integration) // Using Overload() to override shell environment variables (e.g., from AWS SSO) envPaths := []string{ ".env", // Running from test/integration directory "test/integration/.env", // Running from project root filepath.Join("..", "..", ".env"), // Alternative from test/integration } envLoaded := false for _, envPath := range envPaths { if err := godotenv.Overload(envPath); err == nil { s.T().Logf("Loaded environment variables from: %s (overriding shell variables)", envPath) envLoaded = true break } } if !envLoaded { s.T().Log("No .env file found - using environment variables from shell") } // Validate required environment variables requiredEnvVars := map[string]string{ "AWS_REGION": "AWS region where Cognito User Pool is located (e.g., us-east-1)", "COGNITO_USER_POOL_ID": "AWS Cognito User Pool ID (e.g., us-east-1_XXXXXXXXX)", "PERMIT_IO_API_KEY": "Permit.io API key (starts with 'permit_key_')", "PERMIT_IO_PROJECT_ID": "Permit.io project identifier", "PERMIT_IO_ENV_ID": "Permit.io environment identifier (e.g., dev, staging, production)", } missingVars := make([]string, 0) for envVar, description := range requiredEnvVars { if os.Getenv(envVar) == "" { missingVars = append(missingVars, fmt.Sprintf(" - %s: %s", envVar, description)) } } if len(missingVars) > 0 { errorMsg := "\n\nāŒ Missing required environment variables for integration tests\n\n" + "The following environment variables must be set:\n" for _, line := range missingVars { errorMsg += line + "\n" } errorMsg += "\nSetup instructions:\n" + " 1. Copy test/integration/.env.example to test/integration/.env\n" + " 2. Fill in your AWS and Permit.io credentials\n" + " 3. Run tests: go test -tags=integration -v ./test/integration/...\n\n" + "Note: The .env file will be automatically loaded from test/integration/.env\n" + "See test/integration/README.md for detailed setup instructions.\n" s.T().Fatal(errorMsg) } // Initialize AWS Cognito client awsConfig, err := aws.GetAWSConfig(context.Background()) s.Require().NoError(err, "Failed to get AWS config") s.cognitoClient = cognitoidentityprovider.NewFromConfig(awsConfig) s.cognitoConfig = &usermanagement.CognitoConfig{ UserPoolID: os.Getenv("COGNITO_USER_POOL_ID"), Region: os.Getenv("AWS_REGION"), } // Initialize Permit.io client s.httpClient = &http.Client{ Timeout: 30 * time.Second, } defaultTenant := os.Getenv("PERMIT_IO_TENANT") if defaultTenant == "" { defaultTenant = "default" } baseURL := os.Getenv("PERMIT_IO_BASE_URL") if baseURL == "" { baseURL = "https://api.permit.io" } s.permitConfig = &usermanagement.PermitConfig{ APIKey: os.Getenv("PERMIT_IO_API_KEY"), BaseURL: baseURL, DefaultTenant: defaultTenant, } s.testUsers = make([]string, 0) s.permitOnlyUsers = make(map[string]string) s.T().Logf("Integration test suite initialized") s.T().Logf("AWS Region: %s", s.cognitoConfig.Region) s.T().Logf("Cognito User Pool: %s", s.cognitoConfig.UserPoolID) s.T().Logf("Permit.io Base URL: %s", s.permitConfig.BaseURL) } // TearDownSuite runs once after all tests to cleanup test resources. func (s *AdminIntegrationTestSuite) TearDownSuite() { s.T().Log("\n=== Verifying and Cleaning Up Test Users ===") ctx := context.Background() // Check if Permit.io cleanup should be skipped (useful for manual inspection) skipPermitCleanup := os.Getenv("SKIP_PERMITIO_CLEANUP") == "true" if skipPermitCleanup { s.T().Log("āš ļø SKIP_PERMITIO_CLEANUP=true - Permit.io users will NOT be deleted") } for _, email := range s.testUsers { s.T().Logf("\n--- User: %s ---", email) // Check if this is a Permit.io-only user if subjectID, isPermitOnly := s.permitOnlyUsers[email]; isPermitOnly { s.T().Logf("šŸ”µ Permit.io-only user (SubjectID: %s)", subjectID) // Verify user exists in Permit.io roles, err := usermanagement.GetUserRoles(s.httpClient, s.permitConfig, subjectID) if err != nil { s.T().Logf("āŒ User NOT found in Permit.io: %v", err) } else { s.T().Logf("āœ… User found in Permit.io:") s.T().Logf(" - Roles: %v", roles) } // Delete from Permit.io (unless skipped) if skipPermitCleanup { s.T().Logf("ā­ļø Skipping Permit.io cleanup - user left for manual inspection") } else { err = usermanagement.DeletePermitUser(s.httpClient, s.permitConfig, subjectID) if err != nil { s.T().Logf("āš ļø Warning: Failed to delete from Permit.io: %v", err) } else { s.T().Logf("šŸ—‘ļø Deleted from Permit.io") } } continue } // Full integration user - cleanup both Cognito and Permit.io cognitoUser, err := usermanagement.GetCognitoUser(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) if err != nil { s.T().Logf("āŒ User NOT found in Cognito: %v", err) } else { s.T().Logf("āœ… User found in Cognito:") s.T().Logf(" - SubjectID: %s", cognitoUser.SubjectID) s.T().Logf(" - Email: %s", cognitoUser.Email) s.T().Logf(" - Name: %s %s", cognitoUser.FirstName, cognitoUser.LastName) s.T().Logf(" - Enabled: %v", cognitoUser.Enabled) // Verify user exists in Permit.io roles, err := usermanagement.GetUserRoles(s.httpClient, s.permitConfig, cognitoUser.SubjectID) if err != nil { s.T().Logf("āŒ User NOT found in Permit.io: %v", err) } else { s.T().Logf("āœ… User found in Permit.io:") s.T().Logf(" - Roles: %v", roles) } // Delete from Permit.io first (unless skipped) if skipPermitCleanup { s.T().Logf("ā­ļø Skipping Permit.io cleanup - user left for manual inspection") } else { err = usermanagement.DeletePermitUser(s.httpClient, s.permitConfig, cognitoUser.SubjectID) if err != nil { s.T().Logf("āš ļø Warning: Failed to delete from Permit.io: %v", err) } else { s.T().Logf("šŸ—‘ļø Deleted from Permit.io") } } } // Delete from Cognito err = usermanagement.DeleteCognitoUser(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) if err != nil { s.T().Logf("āš ļø Warning: Failed to delete from Cognito: %v", err) } else { s.T().Logf("šŸ—‘ļø Deleted from Cognito") } } s.T().Logf("\n=== Cleanup Complete ===") } // generateTestEmail generates a unique email for testing. func (s *AdminIntegrationTestSuite) generateTestEmail(testName string) string { prefix := os.Getenv("TEST_USER_EMAIL_PREFIX") if prefix == "" { prefix = "integration-test-" } domain := os.Getenv("TEST_USER_DOMAIN") if domain == "" { domain = "example.com" } timestamp := time.Now().Unix() return fmt.Sprintf("%s%s-%d@%s", prefix, testName, timestamp, domain) } // generateTestSubjectID generates a UUID for testing Permit.io without Cognito. // Returns email and subjectID. The email is tracked for cleanup, subjectID is used for Permit.io operations. func (s *AdminIntegrationTestSuite) generateTestSubjectID(testName string) (email string, subjectID string) { email = s.generateTestEmail(testName) subjectID = uuid.New().String() s.testUsers = append(s.testUsers, email) s.permitOnlyUsers[email] = subjectID return email, subjectID } // TestCreateUser tests creating a new user in both Cognito and Permit.io. func (s *AdminIntegrationTestSuite) TestCreateUser() { ctx := context.Background() email := s.generateTestEmail("create") s.testUsers = append(s.testUsers, email) attrs := usermanagement.UserAttributes{ Email: email, FirstName: "Test", LastName: "User", } // Create user user, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create Cognito user") s.Require().NotEmpty(user.SubjectID, "Subject ID should not be empty") s.Equal(email, user.Email) s.Equal("Test", user.FirstName) s.Equal("User", user.LastName) // Create in Permit.io err = usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, user) s.Require().NoError(err, "Failed to create Permit.io user") // Verify user exists in Cognito retrieved, err := usermanagement.GetCognitoUser(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.Require().NoError(err, "Failed to get Cognito user") s.Equal(user.SubjectID, retrieved.SubjectID) } // TestCreateUserIdempotent tests that creating an existing user is idempotent. func (s *AdminIntegrationTestSuite) TestCreateUserIdempotent() { ctx := context.Background() email := s.generateTestEmail("idempotent") s.testUsers = append(s.testUsers, email) attrs := usermanagement.UserAttributes{ Email: email, FirstName: "Idempotent", LastName: "Test", } // Create user first time user1, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create Cognito user first time") // Create in Permit.io err = usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, user1) s.Require().NoError(err, "Failed to create Permit.io user") // Attempt to create same user again should succeed (idempotent behavior tested in handler) exists := usermanagement.UserExistsInCognito(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.True(exists, "User should exist") } // TestGetUser tests retrieving an existing user. func (s *AdminIntegrationTestSuite) TestGetUser() { ctx := context.Background() email := s.generateTestEmail("get") s.testUsers = append(s.testUsers, email) // Create user first attrs := usermanagement.UserAttributes{ Email: email, FirstName: "Get", LastName: "Test", } user, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create user") // Get user retrieved, err := usermanagement.GetCognitoUser(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.Require().NoError(err, "Failed to get user") s.Equal(user.SubjectID, retrieved.SubjectID) s.Equal(email, retrieved.Email) s.Equal("Get", retrieved.FirstName) s.Equal("Test", retrieved.LastName) } // TestUpdateUserAttributes tests updating user attributes in Cognito. func (s *AdminIntegrationTestSuite) TestUpdateUserAttributes() { ctx := context.Background() email := s.generateTestEmail("update") s.testUsers = append(s.testUsers, email) // Create user attrs := usermanagement.UserAttributes{ Email: email, FirstName: "Original", LastName: "Name", } _, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create user") // Update attributes updateAttrs := usermanagement.UserAttributes{ FirstName: "Updated", LastName: "Name", } err = usermanagement.UpdateCognitoUserAttributes(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email, updateAttrs) s.Require().NoError(err, "Failed to update user attributes") // Verify updates retrieved, err := usermanagement.GetCognitoUser(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.Require().NoError(err, "Failed to get updated user") s.Equal("Updated", retrieved.FirstName) s.Equal("Name", retrieved.LastName) } // TestDisableEnableUser tests disabling and enabling a user. func (s *AdminIntegrationTestSuite) TestDisableEnableUser() { ctx := context.Background() email := s.generateTestEmail("disable") s.testUsers = append(s.testUsers, email) // Create user attrs := usermanagement.UserAttributes{ Email: email, FirstName: "Disable", LastName: "Test", } user, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create user") // User should be enabled by default enabled, err := usermanagement.IsCognitoUserEnabled(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.Require().NoError(err, "Failed to check if user is enabled") s.True(enabled, "User should be enabled initially") // Disable user err = usermanagement.DisableCognitoUser(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.Require().NoError(err, "Failed to disable user") // Verify disabled enabled, err = usermanagement.IsCognitoUserEnabled(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.Require().NoError(err, "Failed to check if user is disabled") s.False(enabled, "User should be disabled") // Re-enable user err = usermanagement.EnableCognitoUser(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, user.Username) s.Require().NoError(err, "Failed to enable user") // Verify enabled enabled, err = usermanagement.IsCognitoUserEnabled(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.Require().NoError(err, "Failed to check if user is re-enabled") s.True(enabled, "User should be re-enabled") } // TestDeleteUser tests deleting a user from both systems. func (s *AdminIntegrationTestSuite) TestDeleteUser() { ctx := context.Background() email := s.generateTestEmail("delete") // Create user attrs := usermanagement.UserAttributes{ Email: email, FirstName: "Delete", LastName: "Test", } user, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create user") // Create in Permit.io err = usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, user) s.Require().NoError(err, "Failed to create Permit.io user") // Delete user err = usermanagement.DeleteCognitoUser(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.Require().NoError(err, "Failed to delete Cognito user") // Delete from Permit.io err = usermanagement.DeletePermitUser(s.httpClient, s.permitConfig, user.SubjectID) s.Require().NoError(err, "Failed to delete Permit.io user") // Verify user doesn't exist exists := usermanagement.UserExistsInCognito(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, email) s.False(exists, "User should not exist after deletion") // Don't add to cleanup list since already deleted } // TestListUsers tests listing users with pagination. func (s *AdminIntegrationTestSuite) TestListUsers() { ctx := context.Background() // Create multiple test users numUsers := 3 for i := 0; i < numUsers; i++ { email := s.generateTestEmail(fmt.Sprintf("list-%d", i)) s.testUsers = append(s.testUsers, email) attrs := usermanagement.UserAttributes{ Email: email, FirstName: fmt.Sprintf("User%d", i), LastName: "Test", } _, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create test user %d", i) } // List users (may include other users in the pool) result, err := usermanagement.ListCognitoUsers(ctx, s.cognitoClient, s.cognitoConfig.UserPoolID, 60, nil) s.Require().NoError(err, "Failed to list users") s.NotNil(result, "Result should not be nil") s.NotEmpty(result.Users, "Should have at least some users") // Verify our test users are in the list foundCount := 0 for _, user := range result.Users { for _, testEmail := range s.testUsers { if user.Email == testEmail { foundCount++ } } } s.GreaterOrEqual(foundCount, 1, "Should find at least one of our test users") } // TestRoleAssignment tests assigning and unassigning roles in Permit.io. func (s *AdminIntegrationTestSuite) TestRoleAssignment() { ctx := context.Background() email := s.generateTestEmail("role") s.testUsers = append(s.testUsers, email) // Create user attrs := usermanagement.UserAttributes{ Email: email, FirstName: "Role", LastName: "Test", } user, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create user") // Create in Permit.io err = usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, user) s.Require().NoError(err, "Failed to create Permit.io user") // Try roles defined in permit_policies.yaml - use the first one that exists testRoles := []string{"super_admin", "user_admin", "auditor", "client_user"} var testRole string var roleFound bool for _, role := range testRoles { err = usermanagement.AssignRole(s.httpClient, s.permitConfig, user.SubjectID, role) if err == nil { testRole = role roleFound = true s.T().Logf("āœ… Using role '%s' for testing", testRole) break } // Check if it's a 404 (role doesn't exist) vs other errors if err != nil && !strings.Contains(err.Error(), "404") && !strings.Contains(err.Error(), "NOT_FOUND") { // Some other error occurred, fail the test s.Require().NoError(err, "Failed to assign role %s (unexpected error)", role) } } if !roleFound { s.T().Skip("\nāŒ SKIPPED: No suitable roles found in Permit.io environment.\n\n" + "To run this test, ensure the Permit.io environment has roles defined.\n" + "Expected roles (from permit_policies.yaml):\n" + " - super_admin\n - user_admin\n - auditor\n - client_user\n\n" + "Run: task permit:setup (or use cmd/auth_related/permit.setup/setup_permit)\n" + "Visit: https://app.permit.io") return } // Get roles - verify assignment worked roles, err := usermanagement.GetUserRoles(s.httpClient, s.permitConfig, user.SubjectID) s.Require().NoError(err, "Failed to get user roles") s.Contains(roles, testRole, "User should have the assigned role") s.T().Logf("āœ… User has role '%s': %v", testRole, roles) // Unassign role err = usermanagement.UnassignRole(s.httpClient, s.permitConfig, user.SubjectID, testRole) s.Require().NoError(err, "Failed to unassign role") // Verify role removed roles, err = usermanagement.GetUserRoles(s.httpClient, s.permitConfig, user.SubjectID) s.Require().NoError(err, "Failed to get user roles after unassignment") s.NotContains(roles, testRole, "User should not have the role after unassignment") s.T().Logf("āœ… Role '%s' successfully unassigned. Current roles: %v", testRole, roles) } // ============================================================================ // Permit.io-Specific Integration Tests // ============================================================================ // These tests focus specifically on Permit.io operations independent of Cognito. // They verify that all Permit.io user management functions work correctly. // TestPermitIO_CreateAndGetUser tests creating a user in Permit.io and verifying it exists. func (s *AdminIntegrationTestSuite) TestPermitIO_CreateAndGetUser() { email, subjectID := s.generateTestSubjectID("permitio-create") // Create user in Permit.io with generated UUID permitUser := &usermanagement.CognitoUserResponse{ SubjectID: subjectID, Email: email, FirstName: "PermitIO", LastName: "CreateTest", } err := usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, permitUser) s.Require().NoError(err, "Failed to create Permit.io user") s.T().Logf("āœ… Created user in Permit.io: %s (SubjectID: %s)", email, subjectID) // Verify user exists by getting roles (should return empty list, not error) roles, err := usermanagement.GetUserRoles(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "Failed to get user roles from Permit.io") s.NotNil(roles, "Roles should not be nil") s.Empty(roles, "New user should have no roles initially") s.T().Logf("āœ… Verified user exists in Permit.io with no roles") } // TestPermitIO_AssignMultipleRoles tests assigning multiple roles to a user. func (s *AdminIntegrationTestSuite) TestPermitIO_AssignMultipleRoles() { email, subjectID := s.generateTestSubjectID("permitio-multirole") // Create user in Permit.io permitUser := &usermanagement.CognitoUserResponse{ SubjectID: subjectID, Email: email, FirstName: "PermitIO", LastName: "MultiRoleTest", } err := usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, permitUser) s.Require().NoError(err, "Failed to create Permit.io user") // Try to assign multiple roles from permit_policies.yaml rolesToAssign := []string{"auditor", "client_user"} assignedRoles := make([]string, 0) for _, role := range rolesToAssign { err = usermanagement.AssignRole(s.httpClient, s.permitConfig, subjectID, role) if err == nil { assignedRoles = append(assignedRoles, role) s.T().Logf("āœ… Assigned role '%s'", role) } else if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "NOT_FOUND") { s.T().Logf("āš ļø Role '%s' not found in environment, skipping", role) } else { s.Require().NoError(err, "Unexpected error assigning role %s", role) } } // Verify at least one role was assigned s.NotEmpty(assignedRoles, "Should have assigned at least one role") // Get roles and verify roles, err := usermanagement.GetUserRoles(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "Failed to get user roles") for _, assignedRole := range assignedRoles { s.Contains(roles, assignedRole, "User should have role %s", assignedRole) } s.T().Logf("āœ… Verified user has all assigned roles: %v", roles) // Unassign all roles for _, role := range assignedRoles { err = usermanagement.UnassignRole(s.httpClient, s.permitConfig, subjectID, role) s.Require().NoError(err, "Failed to unassign role %s", role) s.T().Logf("āœ… Unassigned role '%s'", role) } // Verify all roles removed roles, err = usermanagement.GetUserRoles(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "Failed to get user roles after unassignment") s.Empty(roles, "User should have no roles after unassignment") s.T().Logf("āœ… Verified all roles unassigned: %v", roles) } // TestPermitIO_DeleteUser tests deleting a user from Permit.io and verifying it's gone. func (s *AdminIntegrationTestSuite) TestPermitIO_DeleteUser() { email, subjectID := s.generateTestSubjectID("permitio-delete") // Create user in Permit.io permitUser := &usermanagement.CognitoUserResponse{ SubjectID: subjectID, Email: email, FirstName: "PermitIO", LastName: "DeleteTest", } err := usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, permitUser) s.Require().NoError(err, "Failed to create Permit.io user") s.T().Logf("āœ… Created user in Permit.io") // Verify user exists roles, err := usermanagement.GetUserRoles(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "User should exist before deletion") s.T().Logf("āœ… Verified user exists (roles: %v)", roles) // Delete user from Permit.io err = usermanagement.DeletePermitUser(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "Failed to delete Permit.io user") s.T().Logf("āœ… Deleted user from Permit.io") // Verify user no longer exists by attempting to delete again // Note: GetUserRoles returns empty array for non-existent users (normal API behavior) // so we verify deletion by trying to delete again and expecting 404 err = usermanagement.DeletePermitUser(s.httpClient, s.permitConfig, subjectID) s.Error(err, "Deleting non-existent user should return 404 error") s.Contains(err.Error(), "404", "Should get 404 error for deleted user") s.T().Logf("āœ… Verified user deleted (second delete returned 404)") } // TestPermitIO_UserLifecycle tests the complete user lifecycle in Permit.io. func (s *AdminIntegrationTestSuite) TestPermitIO_UserLifecycle() { email, subjectID := s.generateTestSubjectID("permitio-lifecycle") s.T().Log("=== Starting Permit.io User Lifecycle Test ===") // Step 1: Generate test SubjectID s.T().Logf("Step 1: āœ… Generated test SubjectID: %s", subjectID) // Step 2: Create user in Permit.io permitUser := &usermanagement.CognitoUserResponse{ SubjectID: subjectID, Email: email, FirstName: "PermitIO", LastName: "LifecycleTest", } err := usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, permitUser) s.Require().NoError(err, "Failed to create Permit.io user") s.T().Log("Step 2: āœ… Created user in Permit.io") // Step 3: Verify user has no roles initially roles, err := usermanagement.GetUserRoles(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "Failed to get initial roles") s.Empty(roles, "New user should have no roles") s.T().Logf("Step 3: āœ… Verified no initial roles: %v", roles) // Step 4: Assign a role testRole := "auditor" // Use a role from permit_policies.yaml err = usermanagement.AssignRole(s.httpClient, s.permitConfig, subjectID, testRole) if err != nil && (strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "NOT_FOUND")) { // Try alternative role if auditor doesn't exist testRole = "client_user" err = usermanagement.AssignRole(s.httpClient, s.permitConfig, subjectID, testRole) } s.Require().NoError(err, "Failed to assign role") s.T().Logf("Step 4: āœ… Assigned role '%s'", testRole) // Step 5: Verify role was assigned roles, err = usermanagement.GetUserRoles(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "Failed to get roles after assignment") s.Contains(roles, testRole, "User should have the assigned role") s.T().Logf("Step 5: āœ… Verified role assigned: %v", roles) // Step 6: Unassign the role err = usermanagement.UnassignRole(s.httpClient, s.permitConfig, subjectID, testRole) s.Require().NoError(err, "Failed to unassign role") s.T().Logf("Step 6: āœ… Unassigned role '%s'", testRole) // Step 7: Verify role was unassigned roles, err = usermanagement.GetUserRoles(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "Failed to get roles after unassignment") s.NotContains(roles, testRole, "User should not have the role after unassignment") s.T().Logf("Step 7: āœ… Verified role unassigned: %v", roles) // Step 8: Delete user from Permit.io err = usermanagement.DeletePermitUser(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "Failed to delete user") s.T().Log("Step 8: āœ… Deleted user from Permit.io") // Step 9: Verify user is deleted by attempting to delete again (should get 404) err = usermanagement.DeletePermitUser(s.httpClient, s.permitConfig, subjectID) s.Error(err, "Deleting non-existent user should return 404 error") s.Contains(err.Error(), "404", "Should get 404 error for deleted user") s.T().Log("Step 9: āœ… Verified user deleted (second delete returned 404)") s.T().Log("=== Permit.io User Lifecycle Test Complete ===") } // TestPermitIO_IdempotentOperations tests that Permit.io operations handle duplicates gracefully. func (s *AdminIntegrationTestSuite) TestPermitIO_IdempotentOperations() { email, subjectID := s.generateTestSubjectID("permitio-idempotent") // Create user in Permit.io permitUser := &usermanagement.CognitoUserResponse{ SubjectID: subjectID, Email: email, FirstName: "PermitIO", LastName: "IdempotentTest", } err := usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, permitUser) s.Require().NoError(err, "Failed to create Permit.io user first time") s.T().Log("āœ… Created user in Permit.io (first time)") // Try to create the same user again - should handle gracefully err = usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, permitUser) // Note: Depending on implementation, this might succeed (idempotent) or return conflict // Just log the result, don't fail the test if err != nil { s.T().Logf("Creating duplicate user returned error (expected): %v", err) } else { s.T().Log("āœ… Creating duplicate user succeeded (idempotent)") } // Assign a role testRole := "auditor" err = usermanagement.AssignRole(s.httpClient, s.permitConfig, subjectID, testRole) if err != nil && (strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "NOT_FOUND")) { testRole = "client_user" err = usermanagement.AssignRole(s.httpClient, s.permitConfig, subjectID, testRole) } s.Require().NoError(err, "Failed to assign role") s.T().Logf("āœ… Assigned role '%s'", testRole) // Assign the same role again - should handle gracefully err = usermanagement.AssignRole(s.httpClient, s.permitConfig, subjectID, testRole) if err != nil { s.T().Logf("Assigning duplicate role returned error (may be expected): %v", err) } else { s.T().Logf("āœ… Assigning duplicate role succeeded (idempotent)") } // Verify user still has the role (only once) roles, err := usermanagement.GetUserRoles(s.httpClient, s.permitConfig, subjectID) s.Require().NoError(err, "Failed to get user roles") s.Contains(roles, testRole, "User should have the role") // Count occurrences of the role (should be exactly 1) count := 0 for _, r := range roles { if r == testRole { count++ } } s.Equal(1, count, "Role should appear exactly once, not duplicated") s.T().Logf("āœ… Verified role appears exactly once: %v", roles) } // TestPermitIO_CreateUserWithEnvironmentID verifies that when a Cognito user is created // with an EnvironmentID, the corresponding Permit.io user has "environment_id" stored in // its attributes map. This closes the gap where the Cognito side was tested but the // Permit.io attribute propagation was not. func (s *AdminIntegrationTestSuite) TestPermitIO_CreateUserWithEnvironmentID() { ctx := context.Background() email := s.generateTestEmail("permitio-envid") s.testUsers = append(s.testUsers, email) const testEnvID = "integrationtest" // Step 1: Create user in Cognito with EnvironmentID attrs := usermanagement.UserAttributes{ Email: email, FirstName: "PermitEnv", LastName: "Test", EnvironmentID: testEnvID, } cognitoUser, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create Cognito user with EnvironmentID") s.Equal(testEnvID, cognitoUser.EnvironmentID, "Cognito user should have EnvironmentID set") s.T().Logf("Created Cognito user %s (sub=%s, env=%s)", email, cognitoUser.SubjectID, cognitoUser.EnvironmentID) // Step 2: Create user in Permit.io (should propagate environment_id to attributes) err = usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, cognitoUser) s.Require().NoError(err, "Failed to create Permit.io user") s.T().Log("Created user in Permit.io") // Step 3: Fetch the Permit.io user and verify environment_id is in attributes permitUser, err := usermanagement.GetPermitUser(s.httpClient, s.permitConfig, cognitoUser.SubjectID) s.Require().NoError(err, "Failed to get Permit.io user") s.Require().NotNil(permitUser, "Permit.io user should not be nil") s.Require().NotNil(permitUser.Attributes, "Permit.io user attributes should not be nil") envIDAttr, ok := permitUser.Attributes["environment_id"] s.Require().True(ok, "Permit.io user attributes should contain 'environment_id'") s.Equal(testEnvID, envIDAttr, "Permit.io environment_id attribute should match the Cognito environment ID") s.T().Logf("Verified Permit.io user has environment_id=%v", envIDAttr) } // TestPermitIO_CreateUserWithoutEnvironmentID verifies that when a Cognito user is created // without an EnvironmentID (backward-compatible case), the Permit.io user does NOT have // environment_id in its attributes. func (s *AdminIntegrationTestSuite) TestPermitIO_CreateUserWithoutEnvironmentID() { ctx := context.Background() email := s.generateTestEmail("permitio-noenvid") s.testUsers = append(s.testUsers, email) // Create user in Cognito without EnvironmentID attrs := usermanagement.UserAttributes{ Email: email, FirstName: "NoEnv", LastName: "Test", } cognitoUser, err := usermanagement.CreateCognitoUser(ctx, s.cognitoClient, s.cognitoConfig, attrs) s.Require().NoError(err, "Failed to create Cognito user") s.Empty(cognitoUser.EnvironmentID, "Cognito user should have empty EnvironmentID") // Create in Permit.io err = usermanagement.CreatePermitUser(s.httpClient, s.permitConfig, cognitoUser) s.Require().NoError(err, "Failed to create Permit.io user") // Fetch and verify no environment_id attribute permitUser, err := usermanagement.GetPermitUser(s.httpClient, s.permitConfig, cognitoUser.SubjectID) s.Require().NoError(err, "Failed to get Permit.io user") s.Require().NotNil(permitUser) if permitUser.Attributes != nil { _, hasEnvID := permitUser.Attributes["environment_id"] s.False(hasEnvID, "Permit.io user should NOT have environment_id when Cognito user has no env ID") } s.T().Log("Verified Permit.io user has no environment_id attribute (backward compat)") } // TestSuite runs the integration test suite. func TestSuite(t *testing.T) { suite.Run(t, new(AdminIntegrationTestSuite)) }