← Back to list

test-multitenant-isolation
by Async-IO
MCP/A2A/Rest Fitness Intelligence platform.
⭐ 16🍴 2📅 Jan 24, 2026
SKILL.md
name: test-multitenant-isolation description: Validates complete data isolation between tenants, tests cross-tenant access, ensures proper query scoping user-invocable: true
Multi-Tenant Isolation Testing Skill
Purpose
Validates complete data isolation between tenants to prevent catastrophic data leaks. Tests cross-tenant access attempts and ensures all database queries are properly scoped.
CLAUDE.md Compliance
- ✅ Tests use synthetic data (no external dependencies)
- ✅ Deterministic test execution
- ✅ Tests both success and attack scenarios
- ✅ Validates security-critical functionality
Usage
Run this skill:
- After authentication/authorization changes
- After database schema modifications
- Before production deployments
- After tenant-related code changes
- Weekly security audits
Prerequisites
- SQLite or PostgreSQL database
- Test database cleanup (automatic via tempfile)
Commands
Comprehensive Multi-Tenant Test
# Run full multi-tenant isolation test suite
cargo test --test mcp_multitenant_complete_test --features testing -- --nocapture
Quick Isolation Check
# Run specific isolation tests
cargo test multitenant -- --nocapture
# Test cross-tenant access attempts
cargo test test_cross_tenant -- --nocapture
# Test tenant context middleware
cargo test test_tenant_middleware -- --nocapture
Database Query Scoping Validation
# Search for queries without tenant_id filtering
echo "🔍 Checking for unscoped queries..."
rg "SELECT.*FROM.*WHERE" src/ --type rust -A 3 | rg -v "tenant_id" | head -20
# Verify TenantContext usage in routes
echo "🔍 Checking route handler tenant context..."
rg "Extension.*TenantContext" src/routes/ --type rust -n | wc -l
# Check for hardcoded tenant IDs (security issue)
rg -i "tenant.*=.*\"[a-f0-9-]{36}\"" src/ --type rust -n || echo "✓ No hardcoded tenant IDs"
Test Scenarios
Scenario 1: Cross-Tenant Activity Access
// Tenant A creates activity
// Tenant B attempts to read it
// Expected: 403 Forbidden or empty result
Scenario 2: Tenant Context Injection
// Middleware extracts tenant_id from JWT
// All subsequent queries filtered by tenant_id
// Expected: Only tenant's own data visible
Scenario 3: API Key Isolation
// Tenant A's API key used
// Attempt to access Tenant B's data
// Expected: Empty results (not 403 - security through obscurity)
Scenario 4: OAuth Token Isolation
// OAuth tokens stored per tenant
// Tenant A cannot access Tenant B's tokens
// Expected: Null/NotFound
Security Checks
Database Query Patterns
# All queries MUST include tenant_id filter
# Examples of CORRECT patterns:
# ✅ SELECT with tenant_id
SELECT * FROM activities WHERE tenant_id = $1 AND user_id = $2
# ✅ INSERT with tenant_id
INSERT INTO activities (tenant_id, user_id, ...) VALUES ($1, $2, ...)
# ✅ UPDATE with tenant_id
UPDATE activities SET ... WHERE tenant_id = $1 AND id = $2
# ✅ DELETE with tenant_id
DELETE FROM activities WHERE tenant_id = $1 AND id = $2
TenantContext Pattern
// All route handlers must use TenantContext
// ✅ Correct
pub async fn get_activities(
Extension(tenant): Extension<TenantContext>,
Json(params): Json<GetActivitiesParams>,
) -> Result<Json<Activities>, AppError> {
// tenant.tenant_id automatically scopes queries
}
// ❌ Incorrect (missing TenantContext)
pub async fn get_activities(
Json(params): Json<GetActivitiesParams>,
) -> Result<Json<Activities>, AppError> {
// No tenant scoping!
}
Test Output Analysis
Expected Output
test test_tenant_isolation ... ok
test test_cross_tenant_activity_access ... ok (should fail access)
test test_cross_tenant_user_access ... ok (should fail access)
test test_tenant_oauth_isolation ... ok
test test_tenant_api_key_isolation ... ok
test result: ok. 12 passed; 0 failed
Failure Indicators
# ❌ BAD: Cross-tenant access succeeded
test test_cross_tenant_activity_access ... FAILED
Expected: Forbidden or empty
Actual: Returned data from other tenant
# ❌ BAD: Query without tenant_id
SELECT * FROM activities WHERE user_id = $1
(Missing tenant_id filter!)
# ❌ BAD: Tenant ID from request body instead of JWT
let tenant_id = params.tenant_id; // User can forge!
Success Criteria
- ✅ All multi-tenant tests pass
- ✅ Cross-tenant access attempts fail (403 or empty)
- ✅ All database queries include tenant_id filter
- ✅ TenantContext used in all route handlers
- ✅ No hardcoded tenant IDs in code
- ✅ OAuth tokens isolated per tenant
- ✅ API keys isolated per tenant
- ✅ Zero data leakage in logs (PII redaction active)
Related Files
tests/mcp_multitenant_complete_test.rs- Main test suitesrc/tenant/mod.rs- TenantContext definitionsrc/middleware/tenant_middleware.rs- Tenant extractionsrc/database/mod.rs- Scoped database queries
Related Skills
check-no-secrets- Secret detectionvalidate-architecture- Architectural validation
Score
Total Score
65/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
1ヶ月以内に更新
+10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon

