#!/bin/bash # BUD-09 Blob Report Test Suite # This test is created FIRST (TDD) and will FAIL until implementation is added to src/main.c. # # Expected implementation in src/main.c (BUD-09 section): # - handle_report_request() -> Parse and validate NIP-56 kind 1984 report events # - validate_report_event() -> Verify event structure, signature, and required tags # - process_blob_report() -> Store report, optionally take action on reported blobs # - report_get_blob_hashes() -> Extract SHA-256 hashes from x tags # - report_validate_hash() -> Validate SHA-256 format in x tags # # Integration points expected: # - PUT /report endpoint accepts NIP-56 report events # - Server validates event structure and signatures # - Server responds with appropriate HTTP status codes # # Requirements: # - curl, jq, nak (nostr army knife) must be available # - Server should be running at http://localhost:9001 (restart-all.sh) set -e SERVER_URL="http://localhost:9001" REPORT_ENDPOINT="${SERVER_URL}/report" WORKDIR="tests/tmp_bud09" # Test counters TESTS_TOTAL=0 TESTS_PASSED=0 TESTS_FAILED=0 echo "=== BUD-09 Blob Report Test Suite ===" # Prereq checks if ! command -v curl >/dev/null 2>&1; then echo "ERROR: curl not found" exit 1 fi if ! command -v jq >/dev/null 2>&1; then echo "ERROR: jq not found (required for JSON parsing)" exit 1 fi if ! command -v nak >/dev/null 2>&1; then echo "ERROR: nak not found (required for nostr event generation)" echo "Install with: go install github.com/fiatjaf/nak@latest" exit 1 fi # Helper functions log_test() { echo "" echo "=== Test $1: $2 ===" TESTS_TOTAL=$((TESTS_TOTAL + 1)) } validate_response() { local response="$1" local expected_code="$2" local test_name="$3" local http_code=$(echo "$response" | tail -n1 | grep "HTTP_CODE:" | cut -d: -f2) if [ "$http_code" = "$expected_code" ]; then echo "✅ $test_name PASSED (HTTP $http_code)" TESTS_PASSED=$((TESTS_PASSED + 1)) else echo "❌ $test_name FAILED (Expected HTTP $expected_code, got $http_code)" TESTS_FAILED=$((TESTS_FAILED + 1)) fi # Show response body for debugging local body=$(echo "$response" | head -n -1) if [ -n "$body" ]; then echo "Response: $body" fi } generate_report_event() { local blob_hash="$1" local report_type="$2" local content="$3" nak event -k 1984 -c "$content" -t "x=$blob_hash;$report_type" } generate_multi_report_event() { local content="$1" shift local tags="" for arg in "$@"; do local hash=$(echo "$arg" | cut -d'=' -f1) local type=$(echo "$arg" | cut -d'=' -f2) tags="$tags -t x=$hash;$type" done nak event -k 1984 -c "$content" $tags } submit_report() { local event_json="$1" curl -s -w "\nHTTP_CODE:%{http_code}\n" \ -X PUT \ -H "Content-Type: application/json" \ -d "$event_json" \ "$REPORT_ENDPOINT" } # Create temporary working directory mkdir -p "$WORKDIR" # Test data - valid SHA-256 hashes HASH1="deadbeefcafebabe0123456789abcdef0123456789abcdef0123456789abcdef" HASH2="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" HASH3="abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" INVALID_HASH="invalid_hash_format" echo "" echo "Test Configuration:" echo " Server: $SERVER_URL" echo " Report endpoint: $REPORT_ENDPOINT" echo " Working directory: $WORKDIR" echo " Test hashes: $HASH1, $HASH2, $HASH3" # Test 1: Valid Single Blob Report (nudity) log_test 1 "Valid Single Blob Report (nudity)" EVENT1=$(generate_report_event "$HASH1" "nudity" "This image contains inappropriate content") echo "Event: $EVENT1" RESPONSE1=$(submit_report "$EVENT1") validate_response "$RESPONSE1" "200" "Test 1" # Test 2: Multiple Blob Report (malware) log_test 2 "Multiple Blob Report (malware)" EVENT2=$(generate_multi_report_event "Multiple files contain malware" "${HASH1}=malware" "${HASH2}=malware") echo "Event: $EVENT2" RESPONSE2=$(submit_report "$EVENT2") validate_response "$RESPONSE2" "200" "Test 2" # Test 3: Report Types Coverage - nudity log_test 3a "Report Type: nudity" EVENT3A=$(generate_report_event "$HASH1" "nudity" "Nudity content reported") RESPONSE3A=$(submit_report "$EVENT3A") validate_response "$RESPONSE3A" "200" "Test 3a (nudity)" # Test 3: Report Types Coverage - malware log_test 3b "Report Type: malware" EVENT3B=$(generate_report_event "$HASH2" "malware" "Malware content reported") RESPONSE3B=$(submit_report "$EVENT3B") validate_response "$RESPONSE3B" "200" "Test 3b (malware)" # Test 3: Report Types Coverage - profanity log_test 3c "Report Type: profanity" EVENT3C=$(generate_report_event "$HASH3" "profanity" "Profanity content reported") RESPONSE3C=$(submit_report "$EVENT3C") validate_response "$RESPONSE3C" "200" "Test 3c (profanity)" # Test 3: Report Types Coverage - illegal log_test 3d "Report Type: illegal" EVENT3D=$(generate_report_event "$HASH1" "illegal" "Illegal content reported") RESPONSE3D=$(submit_report "$EVENT3D") validate_response "$RESPONSE3D" "200" "Test 3d (illegal)" # Test 3: Report Types Coverage - spam log_test 3e "Report Type: spam" EVENT3E=$(generate_report_event "$HASH2" "spam" "Spam content reported") RESPONSE3E=$(submit_report "$EVENT3E") validate_response "$RESPONSE3E" "200" "Test 3e (spam)" # Test 3: Report Types Coverage - impersonation log_test 3f "Report Type: impersonation" EVENT3F=$(generate_report_event "$HASH3" "impersonation" "Impersonation content reported") RESPONSE3F=$(submit_report "$EVENT3F") validate_response "$RESPONSE3F" "200" "Test 3f (impersonation)" # Test 3: Report Types Coverage - other log_test 3g "Report Type: other" EVENT3G=$(generate_report_event "$HASH1" "other" "Other type of inappropriate content") RESPONSE3G=$(submit_report "$EVENT3G") validate_response "$RESPONSE3G" "200" "Test 3g (other)" # Test 4: Report with Optional Tags (comprehensive NIP-56 structure) log_test 4 "Report with Optional Tags" EVENT4=$(nak event -k 1984 -c "Comprehensive report with all tags" \ -t "x=${HASH1};spam" \ -t "e=1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" \ -t "p=abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890" \ -t "server=https://example.com/blob.jpg") echo "Event: $EVENT4" RESPONSE4=$(submit_report "$EVENT4") validate_response "$RESPONSE4" "200" "Test 4" # Test 5: Missing x Tags Error log_test 5 "Missing x Tags Error" EVENT5=$(nak event -k 1984 -c "Report without x tags" -t "p=somekey") echo "Event: $EVENT5" RESPONSE5=$(submit_report "$EVENT5") validate_response "$RESPONSE5" "400" "Test 5" # Test 6: Invalid SHA-256 Format log_test 6 "Invalid SHA-256 Format" EVENT6=$(generate_report_event "$INVALID_HASH" "nudity" "Invalid hash format test") echo "Event: $EVENT6" RESPONSE6=$(submit_report "$EVENT6") validate_response "$RESPONSE6" "400" "Test 6" # Test 7: Wrong Event Kind log_test 7 "Wrong Event Kind" EVENT7=$(nak event -k 1 -c "Wrong kind test" -t "x=${HASH1};nudity") echo "Event: $EVENT7" RESPONSE7=$(submit_report "$EVENT7") validate_response "$RESPONSE7" "400" "Test 7" # Test 8: Invalid JSON Structure log_test 8 "Invalid JSON Structure" INVALID_JSON='{"invalid":"json","missing":}' echo "Invalid JSON: $INVALID_JSON" RESPONSE8=$(curl -s -w "\nHTTP_CODE:%{http_code}\n" \ -X PUT \ -H "Content-Type: application/json" \ -d "$INVALID_JSON" \ "$REPORT_ENDPOINT") validate_response "$RESPONSE8" "400" "Test 8" # Test 9: Unsupported HTTP Method - GET log_test 9a "Unsupported Method: GET" RESPONSE9A=$(curl -s -w "\nHTTP_CODE:%{http_code}\n" \ -X GET \ "$REPORT_ENDPOINT") validate_response "$RESPONSE9A" "405" "Test 9a (GET)" # Test 9: Unsupported HTTP Method - POST log_test 9b "Unsupported Method: POST" RESPONSE9B=$(curl -s -w "\nHTTP_CODE:%{http_code}\n" \ -X POST \ -H "Content-Type: application/json" \ -d '{"test":"post"}' \ "$REPORT_ENDPOINT") validate_response "$RESPONSE9B" "405" "Test 9b (POST)" # Test 9: Unsupported HTTP Method - DELETE log_test 9c "Unsupported Method: DELETE" RESPONSE9C=$(curl -s -w "\nHTTP_CODE:%{http_code}\n" \ -X DELETE \ "$REPORT_ENDPOINT") validate_response "$RESPONSE9C" "405" "Test 9c (DELETE)" # Test 10: Empty Request Body log_test 10 "Empty Request Body" RESPONSE10=$(curl -s -w "\nHTTP_CODE:%{http_code}\n" \ -X PUT \ -H "Content-Type: application/json" \ "$REPORT_ENDPOINT") validate_response "$RESPONSE10" "400" "Test 10" # Test 11: Unknown Report Type (should be accepted per spec) log_test 11 "Unknown Report Type" EVENT11=$(generate_report_event "$HASH1" "unknown_type" "Unknown report type test") echo "Event: $EVENT11" RESPONSE11=$(submit_report "$EVENT11") validate_response "$RESPONSE11" "200" "Test 11" # Test 12: Invalid Content-Type log_test 12 "Invalid Content-Type" EVENT12=$(generate_report_event "$HASH1" "nudity" "Content type test") RESPONSE12=$(curl -s -w "\nHTTP_CODE:%{http_code}\n" \ -X PUT \ -H "Content-Type: text/plain" \ -d "$EVENT12" \ "$REPORT_ENDPOINT") validate_response "$RESPONSE12" "415" "Test 12" # Test 13: Valid report with empty content field log_test 13 "Empty Content Field" EVENT13=$(generate_report_event "$HASH1" "spam" "") echo "Event: $EVENT13" RESPONSE13=$(submit_report "$EVENT13") validate_response "$RESPONSE13" "200" "Test 13" # Test 14: Very long content field log_test 14 "Long Content Field" LONG_CONTENT=$(printf 'A%.0s' {1..1000}) EVENT14=$(generate_report_event "$HASH1" "other" "$LONG_CONTENT") RESPONSE14=$(submit_report "$EVENT14") validate_response "$RESPONSE14" "200" "Test 14" # Cleanup rm -rf "$WORKDIR" # Test Summary echo "" echo "=== BUD-09 Test Summary ===" echo "Total tests: $TESTS_TOTAL" echo "Passed: $TESTS_PASSED" echo "Failed: $TESTS_FAILED" echo "" if [ "$TESTS_FAILED" -eq 0 ]; then echo "🎉 All tests passed! BUD-09 implementation is working correctly." exit 0 else echo "❌ $TESTS_FAILED test(s) failed. BUD-09 implementation needs fixes." exit 1 fi echo "=== End of BUD-09 Blob Report Test Suite ==="