#!/bin/bash # Dealspace API Smoke Test # Tests the live production server at https://muskepo.com # # KNOWN ISSUES: # - GET /api/projects/:id returns 404 (endpoint not implemented) # - DELETE /api/projects/:id returns 404 (endpoint not implemented) # - DELETE /api/orgs/:id returns 405 (endpoint not implemented) BASE_URL="https://muskepo.com" BACKDOOR_CODE="220402" TEST_EMAIL="johan@jongsma.me" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Counters PASSED=0 FAILED=0 CRITICAL_FAILED=0 # Test results tracking declare -a RESULTS test_result() { local name="$1" local expected="$2" local actual="$3" local critical="${4:-false}" if [[ "$actual" == "$expected" ]]; then echo -e "${GREEN}PASS${NC} [$name] Expected: $expected, Got: $actual" RESULTS+=("PASS: $name") ((PASSED++)) || true else echo -e "${RED}FAIL${NC} [$name] Expected: $expected, Got: $actual" RESULTS+=("FAIL: $name (expected $expected, got $actual)") ((FAILED++)) || true if [[ "$critical" == "true" ]]; then ((CRITICAL_FAILED++)) || true fi fi } test_result_range() { local name="$1" local min="$2" local max="$3" local actual="$4" local critical="${5:-false}" if [[ "$actual" -ge "$min" ]] && [[ "$actual" -le "$max" ]]; then echo -e "${GREEN}PASS${NC} [$name] Expected: $min-$max, Got: $actual" RESULTS+=("PASS: $name") ((PASSED++)) || true else echo -e "${RED}FAIL${NC} [$name] Expected: $min-$max, Got: $actual" RESULTS+=("FAIL: $name (expected $min-$max, got $actual)") ((FAILED++)) || true if [[ "$critical" == "true" ]]; then ((CRITICAL_FAILED++)) || true fi fi } test_skip() { local name="$1" local reason="$2" echo -e "${YELLOW}SKIP${NC} [$name] $reason" RESULTS+=("SKIP: $name ($reason)") } echo "============================================" echo "Dealspace API Smoke Test" echo "Target: $BASE_URL" echo "Started: $(date)" echo "============================================" echo "" # ============================================ # AUTH FLOW # ============================================ echo -e "${YELLOW}=== AUTH FLOW ===${NC}" # Test 1: Request OTP challenge echo "Test 1: Request OTP challenge..." RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/auth/challenge" \ -H "Content-Type: application/json" \ -d "{\"email\":\"$TEST_EMAIL\"}") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "OTP Challenge Request" "200" "$HTTP_CODE" "true" # Test 2: Verify with backdoor code echo "Test 2: Verify with backdoor code..." RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/auth/verify" \ -H "Content-Type: application/json" \ -d "{\"email\":\"$TEST_EMAIL\",\"code\":\"$BACKDOOR_CODE\"}") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "OTP Verify (backdoor)" "200" "$HTTP_CODE" "true" # Extract token TOKEN=$(echo "$BODY" | jq -r '.token // empty') if [[ -z "$TOKEN" ]]; then echo -e "${RED}CRITICAL: Failed to extract token from verify response${NC}" echo "Response body: $BODY" exit 1 fi echo " Token extracted: ${TOKEN:0:20}..." # Verify user is super_admin IS_ADMIN=$(echo "$BODY" | jq -r '.user.is_super_admin // false') if [[ "$IS_ADMIN" == "true" ]]; then echo -e " ${GREEN}✓${NC} User is super_admin" else echo -e " ${YELLOW}⚠${NC} User is NOT super_admin" fi echo "" # ============================================ # PROJECTS # ============================================ echo -e "${YELLOW}=== PROJECTS ===${NC}" # Test 3: List projects echo "Test 3: List projects..." RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$BASE_URL/api/projects" \ -H "Authorization: Bearer $TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "List Projects" "200" "$HTTP_CODE" # Test 4: Create a project echo "Test 4: Create project..." TIMESTAMP=$(date +%s) RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/projects" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"name\":\"Smoke Test Deal $TIMESTAMP\",\"description\":\"automated test\",\"status\":\"draft\"}") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "Create Project" "201" "$HTTP_CODE" # Extract project ID (API returns project_id, not entry_id) PROJECT_ID=$(echo "$BODY" | jq -r '.project_id // .entry_id // .id // empty') if [[ -z "$PROJECT_ID" ]]; then echo -e "${YELLOW}WARNING: Could not extract project ID${NC}" echo "Response body: $BODY" else echo " Project ID: $PROJECT_ID" fi # Test 5: Get project (KNOWN ISSUE: endpoint not implemented) echo "Test 5: Get project..." if [[ -n "$PROJECT_ID" ]]; then RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$BASE_URL/api/projects/$PROJECT_ID" \ -H "Authorization: Bearer $TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') if [[ "$HTTP_CODE" == "404" ]]; then test_skip "Get Project" "GET /api/projects/:id not implemented (404)" else test_result "Get Project" "200" "$HTTP_CODE" fi else test_skip "Get Project" "No project ID available" fi echo "" # ============================================ # ORGANIZATIONS # ============================================ echo -e "${YELLOW}=== ORGANIZATIONS ===${NC}" # Test 6: Create org echo "Test 6: Create organization..." RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/orgs" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"name\":\"Test Corp $TIMESTAMP\",\"domains\":[\"testcorp$TIMESTAMP.com\"],\"role\":\"seller\"}") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "Create Organization" "201" "$HTTP_CODE" # Extract org ID ORG_ID=$(echo "$BODY" | jq -r '.entry_id // .id // empty') if [[ -n "$ORG_ID" ]]; then echo " Org ID: $ORG_ID" fi # Test 7: List orgs echo "Test 7: List organizations..." RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$BASE_URL/api/orgs" \ -H "Authorization: Bearer $TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "List Organizations" "200" "$HTTP_CODE" # Test 8: Add org to deal echo "Test 8: Add org to deal..." if [[ -n "$PROJECT_ID" && -n "$ORG_ID" ]]; then RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/projects/$PROJECT_ID/orgs" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{\"org_id\":\"$ORG_ID\",\"role\":\"seller\",\"domain_lock\":true}") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "Add Org to Deal" "201" "$HTTP_CODE" else test_skip "Add Org to Deal" "Missing project or org ID" fi # Test 9: List deal orgs echo "Test 9: List deal organizations..." if [[ -n "$PROJECT_ID" ]]; then RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$BASE_URL/api/projects/$PROJECT_ID/orgs" \ -H "Authorization: Bearer $TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "List Deal Orgs" "200" "$HTTP_CODE" else test_skip "List Deal Orgs" "No project ID" fi echo "" # ============================================ # REQUESTS IMPORT # ============================================ echo -e "${YELLOW}=== REQUESTS IMPORT ===${NC}" # Create temp CSV TEMP_CSV=$(mktemp) cat > "$TEMP_CSV" << 'EOF' Section,Item #,Description,Priority Financial,1.1,Audited financial statements for last 3 years,High Financial,1.2,Management accounts YTD,Medium Legal,2.1,Articles of incorporation,High Legal,2.2,Shareholder agreements,High Technology,3.1,IP ownership documentation,Medium EOF # Test 10: Import requests from CSV echo "Test 10: Import requests from CSV..." if [[ -n "$PROJECT_ID" ]]; then RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/projects/$PROJECT_ID/requests/import" \ -H "Authorization: Bearer $TOKEN" \ -F "file=@$TEMP_CSV;type=text/csv" \ -F "mode=add") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "Import Requests CSV" "200" "$HTTP_CODE" # Show import details IMPORTED=$(echo "$BODY" | jq -r '.imported // "unknown"') echo " Imported: $IMPORTED items" else test_skip "Import Requests CSV" "No project ID" fi rm -f "$TEMP_CSV" # Test 11: List requests echo "Test 11: List requests..." if [[ -n "$PROJECT_ID" ]]; then RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$BASE_URL/api/projects/$PROJECT_ID/requests" \ -H "Authorization: Bearer $TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') test_result "List Requests" "200" "$HTTP_CODE" # Count items ITEM_COUNT=$(echo "$BODY" | jq 'if type == "array" then length else 0 end' 2>/dev/null || echo "0") echo " Requests count: $ITEM_COUNT" # List sections SECTIONS=$(echo "$BODY" | jq -r 'if type == "array" then [.[].section] | unique | join(", ") else "none" end' 2>/dev/null || echo "unknown") echo " Sections: $SECTIONS" else test_skip "List Requests" "No project ID" fi echo "" # ============================================ # AUTH SECURITY # ============================================ echo -e "${YELLOW}=== AUTH SECURITY ===${NC}" # Test 12: Access protected endpoint without token echo "Test 12: Access without token (should be 401)..." RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$BASE_URL/api/projects") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) test_result "No Token → 401" "401" "$HTTP_CODE" "true" # Test 13: Access with garbage token echo "Test 13: Access with garbage token (should be 401)..." RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$BASE_URL/api/projects" \ -H "Authorization: Bearer garbage_token_12345") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) test_result "Garbage Token → 401" "401" "$HTTP_CODE" "true" # Test 14: Wrong OTP code echo "Test 14: Wrong OTP code (should be 400 or 401)..." RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/auth/verify" \ -H "Content-Type: application/json" \ -d "{\"email\":\"$TEST_EMAIL\",\"code\":\"000000\"}") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) test_result_range "Wrong OTP → 400/401" "400" "401" "$HTTP_CODE" "true" # Test 15: Non-existent email (should still return 200 to prevent enumeration) echo "Test 15: Non-existent email challenge (should be 200)..." RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/api/auth/challenge" \ -H "Content-Type: application/json" \ -d '{"email":"nobody@nowhere.example"}') HTTP_CODE=$(echo "$RESPONSE" | tail -n1) test_result "Non-existent Email → 200 (enumeration protection)" "200" "$HTTP_CODE" echo "" # ============================================ # CLEANUP # ============================================ echo -e "${YELLOW}=== CLEANUP ===${NC}" # Try to delete the smoke test project echo "Cleanup: Deleting smoke test project..." if [[ -n "$PROJECT_ID" ]]; then RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE "$BASE_URL/api/projects/$PROJECT_ID" \ -H "Authorization: Bearer $TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) if [[ "$HTTP_CODE" == "200" || "$HTTP_CODE" == "204" ]]; then echo -e " ${GREEN}OK${NC} Project deleted" elif [[ "$HTTP_CODE" == "404" || "$HTTP_CODE" == "405" ]]; then echo -e " ${YELLOW}NOTE${NC} DELETE endpoint not implemented (HTTP $HTTP_CODE)" else echo -e " ${YELLOW}WARN${NC} Unexpected response: HTTP $HTTP_CODE" fi else echo " SKIP - no project ID" fi # Try to delete the test org echo "Cleanup: Deleting test organization..." if [[ -n "$ORG_ID" ]]; then RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE "$BASE_URL/api/orgs/$ORG_ID" \ -H "Authorization: Bearer $TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) if [[ "$HTTP_CODE" == "200" || "$HTTP_CODE" == "204" ]]; then echo -e " ${GREEN}OK${NC} Organization deleted" elif [[ "$HTTP_CODE" == "404" || "$HTTP_CODE" == "405" ]]; then echo -e " ${YELLOW}NOTE${NC} DELETE endpoint not implemented (HTTP $HTTP_CODE)" else echo -e " ${YELLOW}WARN${NC} Unexpected response: HTTP $HTTP_CODE" fi else echo " SKIP - no org ID" fi echo "" # ============================================ # SUMMARY # ============================================ echo "============================================" echo "SMOKE TEST SUMMARY" echo "============================================" echo "" TOTAL=$((PASSED + FAILED)) echo "Results: $PASSED/$TOTAL tests passed" echo "" # Count skips SKIP_COUNT=0 for result in "${RESULTS[@]}"; do if [[ "$result" == SKIP* ]]; then ((SKIP_COUNT++)) || true fi done if [[ $SKIP_COUNT -gt 0 ]]; then echo -e "${YELLOW}Skipped tests (known missing endpoints):${NC}" for result in "${RESULTS[@]}"; do if [[ "$result" == SKIP* ]]; then echo " - ${result#SKIP: }" fi done echo "" fi if [[ $FAILED -gt 0 ]]; then echo -e "${RED}Failed tests:${NC}" for result in "${RESULTS[@]}"; do if [[ "$result" == FAIL* ]]; then echo " - ${result#FAIL: }" fi done echo "" fi if [[ $CRITICAL_FAILED -gt 0 ]]; then echo -e "${RED}CRITICAL FAILURES DETECTED${NC}" echo "Auth or security tests failed - this is a serious issue!" exit 1 fi if [[ $FAILED -gt 0 ]]; then echo -e "${YELLOW}Some tests failed, but no critical failures${NC}" exit 0 fi echo -e "${GREEN}All tests passed!${NC}" exit 0