Merged in feature/admin-api (pull request #191)
admin api and associated tools * in progress admin api started and permit.io setup tool started * docs * build fix * integration tests passing * new permit variables * fix permit * fix delete regex * fix delete response * docs * docs
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# AWS Configuration for Integration Tests
|
||||
# These credentials must have permissions to manage users in the specified Cognito User Pool
|
||||
|
||||
# AWS Region where your Cognito User Pool is located
|
||||
AWS_REGION=us-east-1
|
||||
|
||||
# AWS Credentials
|
||||
# Option 1: Use IAM user credentials
|
||||
AWS_ACCESS_KEY_ID=your_access_key_here
|
||||
AWS_SECRET_ACCESS_KEY=your_secret_key_here
|
||||
|
||||
# Option 2: Use temporary credentials (SSO/STS)
|
||||
# AWS_SESSION_TOKEN=your_session_token_here
|
||||
|
||||
# Cognito Configuration
|
||||
COGNITO_USER_POOL_ID=us-east-1_XXXXXXXXX
|
||||
|
||||
# Optional: Cognito Client ID if needed for JWT generation
|
||||
# COGNITO_CLIENT_ID=your_client_id_here
|
||||
|
||||
# Suppress Cognito welcome emails to avoid hitting the 50 emails/day limit
|
||||
# Set to "true" for integration tests, leave unset or set to "false" for production
|
||||
COGNITO_SUPPRESS_EMAILS=true
|
||||
|
||||
# Skip Permit.io cleanup after tests (useful for manual inspection of created users)
|
||||
# Set to "true" to leave users in Permit.io after tests complete
|
||||
# Remember to manually delete test users afterward to avoid clutter
|
||||
SKIP_PERMITIO_CLEANUP=false
|
||||
|
||||
# Permit.io Configuration
|
||||
# Get these from your Permit.io dashboard
|
||||
|
||||
# Permit.io API Key (starts with "permit_key_")
|
||||
PERMIT_IO_API_KEY=permit_key_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
# Permit.io Project ID
|
||||
PERMIT_IO_PROJECT_ID=your_project_id_here
|
||||
|
||||
# Permit.io Environment ID (e.g., "dev", "staging", "production")
|
||||
PERMIT_IO_ENV_ID=dev
|
||||
|
||||
# Permit.io Tenant (usually "default")
|
||||
PERMIT_IO_TENANT=default
|
||||
|
||||
# Optional: Permit.io Base URL (defaults to https://api.permit.io)
|
||||
# PERMIT_IO_BASE_URL=https://api.permit.io
|
||||
|
||||
# Test Configuration
|
||||
# These control how test user emails are generated
|
||||
|
||||
# Prefix for test user emails (helps identify test users)
|
||||
TEST_USER_EMAIL_PREFIX=integration-test-
|
||||
|
||||
# Domain for test user emails
|
||||
TEST_USER_DOMAIN=example.com
|
||||
|
||||
# Example: With the above settings, test users will have emails like:
|
||||
# integration-test-create-1697123456@example.com
|
||||
@@ -0,0 +1,410 @@
|
||||
# Admin User Management Integration Tests
|
||||
|
||||
This directory contains integration tests for admin user management functionality that use **real AWS Cognito and Permit.io APIs** (no mocks).
|
||||
|
||||
## Overview
|
||||
|
||||
These tests validate the complete user management workflow including:
|
||||
- User creation in AWS Cognito and Permit.io
|
||||
- User retrieval and attribute updates
|
||||
- User enable/disable operations
|
||||
- User deletion from both systems
|
||||
- Role assignment and unassignment in Permit.io
|
||||
- User listing with pagination
|
||||
- Idempotent operations
|
||||
|
||||
## Why Integration Tests Are Separate
|
||||
|
||||
The admin user management code is **excluded from standard CI/CD coverage requirements** because:
|
||||
1. Free tier LocalStack doesn't support AWS Cognito
|
||||
2. Integration tests require real AWS credentials
|
||||
3. Integration tests require real Permit.io API access
|
||||
4. Tests create and modify real user accounts
|
||||
5. Tests should not run automatically in CI/CD pipelines
|
||||
|
||||
These tests are designed for **manual execution** during development and pre-production validation.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### AWS Requirements
|
||||
use `task aws:login` then
|
||||
`eval $(aws configure export-credentials --profile aarete --format env)`
|
||||
to set fresh credentials for the test to use.
|
||||
|
||||
|
||||
1. **AWS Account** with access to Cognito User Pool
|
||||
2. **IAM User or Role** with the following permissions:
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"cognito-idp:AdminCreateUser",
|
||||
"cognito-idp:AdminDeleteUser",
|
||||
"cognito-idp:AdminGetUser",
|
||||
"cognito-idp:AdminUpdateUserAttributes",
|
||||
"cognito-idp:AdminDisableUser",
|
||||
"cognito-idp:AdminEnableUser",
|
||||
"cognito-idp:ListUsers"
|
||||
],
|
||||
"Resource": "arn:aws:cognito-idp:REGION:ACCOUNT_ID:userpool/POOL_ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. **Cognito User Pool ID** - Get this from AWS Console or CLI
|
||||
|
||||
### Permit.io Requirements
|
||||
|
||||
1. **Permit.io Account** with API access
|
||||
2. **API Key** with permissions to:
|
||||
- Create users
|
||||
- Delete users
|
||||
- Assign/unassign roles
|
||||
- Read user roles
|
||||
3. **Project ID** and **Environment ID** from Permit.io dashboard
|
||||
4. **Roles configured** in Permit.io matching your `permit_policies.yaml`:
|
||||
- `super_admin`
|
||||
- `user_admin`
|
||||
- `auditor`
|
||||
- `client_user`
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### Step 1: Create Environment File
|
||||
|
||||
```bash
|
||||
cd test/integration
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### Step 2: Configure Credentials
|
||||
|
||||
Edit `test/integration/.env` and fill in your actual credentials:
|
||||
|
||||
```bash
|
||||
# AWS Configuration
|
||||
AWS_REGION=us-east-1
|
||||
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
|
||||
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||||
COGNITO_USER_POOL_ID=us-east-1_AbCdEfGhI
|
||||
|
||||
# Suppress welcome emails to avoid AWS Cognito's 50 emails/day limit
|
||||
COGNITO_SUPPRESS_EMAILS=true
|
||||
|
||||
# Skip Permit.io cleanup (set to true to inspect users after tests)
|
||||
SKIP_PERMITIO_CLEANUP=false
|
||||
|
||||
# Permit.io Configuration
|
||||
PERMIT_IO_API_KEY=permit_key_1234567890abcdef
|
||||
PERMIT_IO_PROJECT_ID=my-project-123
|
||||
PERMIT_IO_ENV_ID=dev
|
||||
PERMIT_IO_TENANT=default
|
||||
|
||||
# Test Configuration
|
||||
TEST_USER_EMAIL_PREFIX=int-test-
|
||||
TEST_USER_DOMAIN=example.com
|
||||
```
|
||||
|
||||
**IMPORTANT:** Never commit the `.env` file to git! It contains sensitive credentials.
|
||||
|
||||
### Step 3: Verify Permit.io Roles
|
||||
|
||||
**Note:** The test suite automatically loads environment variables from `test/integration/.env` when you run the tests. You do NOT need to manually source the file.
|
||||
|
||||
Ensure the following roles exist in your Permit.io environment (as defined in `cmd/cognito_test/permit.setup/permit_policies.yaml`):
|
||||
- `super_admin`
|
||||
- `user_admin`
|
||||
- `auditor`
|
||||
- `client_user`
|
||||
|
||||
You can create roles through the Permit.io dashboard, API, or use the setup tool at `cmd/cognito_test/permit.setup/`.
|
||||
|
||||
## Running the Tests
|
||||
|
||||
### Run All Integration Tests (13 total)
|
||||
|
||||
```bash
|
||||
go test -tags=integration -v ./test/integration/...
|
||||
```
|
||||
|
||||
This runs:
|
||||
- **8 integrated tests** (Cognito + Permit.io)
|
||||
- **5 Permit.io-only tests** (no Cognito calls)
|
||||
|
||||
### Run Only Integrated Tests (Cognito + Permit.io)
|
||||
|
||||
```bash
|
||||
go test -tags=integration -v -run 'TestSuite/Test[^P]' ./test/integration/...
|
||||
```
|
||||
|
||||
This excludes tests starting with `TestPermitIO_`.
|
||||
|
||||
### Run Only Permit.io Tests (No Cognito)
|
||||
|
||||
```bash
|
||||
go test -tags=integration -v -run 'TestSuite/TestPermitIO' ./test/integration/...
|
||||
```
|
||||
|
||||
Useful when you've hit AWS Cognito's email limit or want to test Permit.io in isolation.
|
||||
|
||||
### Run a Specific Test
|
||||
|
||||
```bash
|
||||
go test -tags=integration -v -run TestSuite/TestCreateUser ./test/integration/...
|
||||
```
|
||||
|
||||
### Run via Task Command
|
||||
|
||||
Add this task to your Taskfile.yml:
|
||||
|
||||
```yaml
|
||||
integration:admin:
|
||||
desc: "Run admin user management integration tests (requires real AWS/Permit.io credentials)"
|
||||
dir: test/integration
|
||||
cmds:
|
||||
- |
|
||||
if [ ! -f .env ]; then
|
||||
echo "❌ Error: test/integration/.env not found"
|
||||
echo "Copy .env.example to .env and configure your credentials"
|
||||
exit 1
|
||||
fi
|
||||
- go test -tags=integration -v ./...
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
task integration:admin
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
The test suite includes **13 integration tests** organized into two categories:
|
||||
|
||||
### Integrated Tests (8 tests - Cognito + Permit.io)
|
||||
|
||||
These tests validate the complete user management workflow across both systems:
|
||||
|
||||
| Test | Description |
|
||||
|------|-------------|
|
||||
| `TestCreateUser` | Creates a new user in both Cognito and Permit.io |
|
||||
| `TestCreateUserIdempotent` | Verifies idempotent user creation behavior |
|
||||
| `TestGetUser` | Retrieves an existing user's details from Cognito |
|
||||
| `TestUpdateUserAttributes` | Updates user's first name and last name in Cognito |
|
||||
| `TestDisableEnableUser` | Disables and re-enables a user account in Cognito |
|
||||
| `TestDeleteUser` | Deletes user from both Cognito and Permit.io |
|
||||
| `TestListUsers` | Lists users with pagination support from Cognito |
|
||||
| `TestRoleAssignment` | Assigns and unassigns roles in Permit.io for Cognito user |
|
||||
|
||||
**Note:** These tests require AWS credentials and will send emails unless `COGNITO_SUPPRESS_EMAILS=true`.
|
||||
|
||||
### Permit.io-Only Tests (5 tests - No Cognito)
|
||||
|
||||
These tests validate Permit.io functionality in isolation using generated UUIDs:
|
||||
|
||||
| Test | Description |
|
||||
|------|-------------|
|
||||
| `TestPermitIO_CreateAndGetUser` | Creates user in Permit.io and verifies it exists |
|
||||
| `TestPermitIO_AssignMultipleRoles` | Assigns/unassigns multiple roles (auditor, client_user) |
|
||||
| `TestPermitIO_DeleteUser` | Deletes user and verifies with 404 response |
|
||||
| `TestPermitIO_UserLifecycle` | Complete 9-step user lifecycle (create → roles → delete) |
|
||||
| `TestPermitIO_IdempotentOperations` | Tests duplicate user/role operations are idempotent |
|
||||
|
||||
**Note:** These tests do NOT call AWS Cognito and can run unlimited times per day.
|
||||
|
||||
## Test User Management
|
||||
|
||||
### Automatic Cleanup
|
||||
|
||||
The test suite implements automatic cleanup in the `TearDownSuite` method:
|
||||
- All test users are tracked during creation
|
||||
- After all tests complete, users are automatically deleted from both Cognito and Permit.io
|
||||
- If cleanup fails, warnings are logged but tests still pass
|
||||
- **Optional:** Set `SKIP_PERMITIO_CLEANUP=true` to preserve Permit.io users for manual inspection (see "Manual Inspection of Test Users" section)
|
||||
|
||||
### Manual Cleanup
|
||||
|
||||
If tests are interrupted and cleanup doesn't run:
|
||||
|
||||
```bash
|
||||
# List users in Cognito
|
||||
aws cognito-idp list-users --user-pool-id YOUR_POOL_ID
|
||||
|
||||
# Delete a user from Cognito
|
||||
aws cognito-idp admin-delete-user \
|
||||
--user-pool-id YOUR_POOL_ID \
|
||||
--username user@example.com
|
||||
|
||||
# Delete from Permit.io (requires API call)
|
||||
curl -X DELETE \
|
||||
"https://api.permit.io/v2/facts/PROJECT_ID/ENV_ID/users/SUBJECT_ID" \
|
||||
-H "Authorization: Bearer YOUR_API_KEY"
|
||||
```
|
||||
|
||||
### Test Email Format
|
||||
|
||||
Test users are created with emails in this format:
|
||||
```
|
||||
{PREFIX}{TEST_NAME}-{TIMESTAMP}@{DOMAIN}
|
||||
```
|
||||
|
||||
Examples:
|
||||
- Integrated test: `int-test-create-1697123456@example.com`
|
||||
- Permit.io test: `int-test-permitio-create-1697123456@example.com`
|
||||
|
||||
This makes it easy to identify and clean up test users. You can customize the prefix and domain using environment variables:
|
||||
- `TEST_USER_EMAIL_PREFIX` (default: `int-test-`)
|
||||
- `TEST_USER_DOMAIN` (default: `example.com`)
|
||||
|
||||
## AWS Cognito Email Limits
|
||||
|
||||
AWS Cognito has a **daily limit of 50 emails** when using the default email service. This limit:
|
||||
- Applies to welcome emails sent during user creation
|
||||
- Resets daily at **09:00 UTC**
|
||||
- Is shared across **all user pools** in your AWS account
|
||||
- Cannot be increased without configuring Amazon SES
|
||||
|
||||
### Email Suppression for Testing
|
||||
|
||||
To avoid hitting this limit during integration testing, the test suite uses the `COGNITO_SUPPRESS_EMAILS=true` environment variable. When set:
|
||||
|
||||
- ✅ No welcome emails are sent to test users
|
||||
- ✅ Users are still created successfully with `email_verified: true`
|
||||
- ✅ Tests can run unlimited times per day
|
||||
- ✅ All user management operations work normally
|
||||
|
||||
**This is the recommended approach for integration tests.**
|
||||
|
||||
### If You Need to Test Email Delivery
|
||||
|
||||
For production environments or when you need to test actual email delivery:
|
||||
|
||||
1. **Configure Amazon SES** with your Cognito User Pool
|
||||
2. **Move SES out of sandbox mode** (requires AWS support ticket, 24hr response)
|
||||
3. **Email limits increase to 50,000/day** in SES production mode
|
||||
|
||||
See [AWS Cognito Email Settings Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-email.html) for setup instructions.
|
||||
|
||||
## Manual Inspection of Test Users
|
||||
|
||||
To inspect users created during tests in the Permit.io dashboard:
|
||||
|
||||
1. **Set the skip cleanup flag** in `test/integration/.env`:
|
||||
```bash
|
||||
SKIP_PERMITIO_CLEANUP=true
|
||||
```
|
||||
|
||||
2. **Run the Permit.io-only tests:**
|
||||
```bash
|
||||
go test -tags=integration -v -run 'TestSuite/TestPermitIO' ./test/integration/...
|
||||
```
|
||||
|
||||
3. **Check test output** for user details:
|
||||
```
|
||||
🔵 Permit.io-only user (SubjectID: cbfc1ba6-81a1-40e1-8e4d-14950737c08f)
|
||||
✅ User found in Permit.io:
|
||||
- Roles: [auditor]
|
||||
⏭️ Skipping Permit.io cleanup - user left for manual inspection
|
||||
```
|
||||
|
||||
4. **Log into Permit.io dashboard** and inspect the users with the SubjectIDs from the test output
|
||||
|
||||
5. **Clean up manually** when done:
|
||||
- In Permit.io UI: Delete the test users
|
||||
- Or re-run tests with `SKIP_PERMITIO_CLEANUP=false`
|
||||
|
||||
**Note:** Cognito users (if any) are still cleaned up automatically to avoid AWS resource charges. Only Permit.io users are preserved when this flag is set.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: Required environment variable not set
|
||||
|
||||
**Solution:** Ensure all required variables are set in `test/integration/.env`
|
||||
|
||||
### Error: User pool not found
|
||||
|
||||
**Solution:** Verify `COGNITO_USER_POOL_ID` is correct and your AWS credentials have access
|
||||
|
||||
### Error: Permit.io API authentication failed
|
||||
|
||||
**Solution:**
|
||||
- Verify `PERMIT_IO_API_KEY` is correct
|
||||
- Check that the API key has not expired
|
||||
- Ensure the API key has correct permissions
|
||||
|
||||
### Error: Role not found in Permit.io
|
||||
|
||||
**Solution:** Create the required roles in your Permit.io environment or update test to use existing roles
|
||||
|
||||
### Error: LimitExceededException - Exceeded daily email limit
|
||||
|
||||
```
|
||||
api error LimitExceededException: Exceeded daily email limit for the operation or the account.
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
- Ensure `COGNITO_SUPPRESS_EMAILS=true` is set in `test/integration/.env`
|
||||
- The email limit resets at 09:00 UTC each day
|
||||
- For production use, configure Amazon SES with your user pool (see AWS Cognito Email Limits section above)
|
||||
|
||||
### Tests hang or timeout
|
||||
|
||||
**Solution:**
|
||||
- Check network connectivity to AWS and Permit.io
|
||||
- Verify AWS credentials are not expired (especially for SSO/temporary credentials)
|
||||
- Increase timeout if needed (edit `httpClient.Timeout` in test suite)
|
||||
|
||||
### Cleanup warnings
|
||||
|
||||
**Solution:** Warnings during cleanup are usually okay (e.g., user already deleted). However, if you see many failures:
|
||||
- Check AWS credentials are still valid
|
||||
- Verify Permit.io API key permissions
|
||||
- Manually clean up orphaned test users
|
||||
|
||||
## CI/CD Exclusion
|
||||
|
||||
The admin handler code is **intentionally excluded** from CI/CD coverage checks:
|
||||
|
||||
**Excluded files in `scripts/tests.yml`:**
|
||||
- `api/queryAPI/adminHandlers.go`
|
||||
- `internal/usermanagement/audit.go`
|
||||
- `internal/usermanagement/cognito.go`
|
||||
- `internal/usermanagement/permitio.go`
|
||||
- `internal/usermanagement/types.go`
|
||||
|
||||
This allows the main test suite to pass without requiring cloud credentials.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **Never commit credentials** - The `.env` file is gitignored
|
||||
2. **Use test environments** - Don't run against production Cognito/Permit.io
|
||||
3. **Limit IAM permissions** - Use least privilege for test credentials
|
||||
4. **Rotate credentials** - Regularly rotate API keys and access keys
|
||||
5. **Monitor test accounts** - Review test user creation in CloudWatch/Permit.io logs
|
||||
6. **Clean up regularly** - Ensure test users are deleted after runs
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements for the integration test suite:
|
||||
|
||||
- [ ] Add tests for concurrent user operations
|
||||
- [ ] Test bulk user creation/deletion
|
||||
- [ ] Add tests for edge cases (special characters in names, etc.)
|
||||
- [ ] Test Cognito password reset flow
|
||||
- [ ] Test MFA enrollment/verification
|
||||
- [ ] Add performance benchmarks
|
||||
- [ ] Test rate limiting behavior
|
||||
- [ ] Add tests for invalid/malformed requests
|
||||
- [ ] Test permission boundary scenarios in Permit.io
|
||||
- [ ] Add chaos testing (network failures, timeouts, etc.)
|
||||
|
||||
## Support
|
||||
|
||||
For issues with:
|
||||
- **AWS Cognito**: Check AWS documentation or contact AWS Support
|
||||
- **Permit.io**: Check Permit.io documentation or contact support
|
||||
- **Test suite**: Open an issue in the project repository
|
||||
@@ -0,0 +1,785 @@
|
||||
//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"),
|
||||
ProjectID: os.Getenv("PERMIT_IO_PROJECT_ID"),
|
||||
EnvID: os.Getenv("PERMIT_IO_ENV_ID"),
|
||||
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 Project: %s", s.permitConfig.ProjectID)
|
||||
s.T().Logf("Permit.io Environment: %s", s.permitConfig.EnvID)
|
||||
}
|
||||
|
||||
// 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/cognito_test/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)
|
||||
}
|
||||
|
||||
// TestSuite runs the integration test suite.
|
||||
func TestSuite(t *testing.T) {
|
||||
suite.Run(t, new(AdminIntegrationTestSuite))
|
||||
}
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
go test -tags=integration -v -run 'TestSuite/TestPermitIO' ./...
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
go test -tags=integration -v ./...
|
||||
Reference in New Issue
Block a user