c668485e6f
cognito and permit shared prod environment support * code complete * user creattion tool test harness
859 lines
33 KiB
Go
859 lines
33 KiB
Go
//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))
|
|
}
|