opticparse-python / run_tests.py
Nanny7's picture
initial deploy
bcf46c3
Raw
History Blame Contribute Delete
13.8 kB
import urllib.request
import ssl
import time
import json
import uuid
import os
print('\n=== SECTION 3: Generate Test API Key ===')
SUPABASE_URL = 'https://xxmvhvxeglsjbewlouqg.supabase.co'
SERVICE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh4bXZodnhlZ2xzamJld2xvdXFnIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc4MjkwMjUxMSwiZXhwIjoyMDk4NDc4NTExfQ.3-uJVjh8FDP8dLar2A6pLRs1K0O5I8lyZepZk7NizJU'
email = f'verify_{uuid.uuid4().hex[:6]}@test.com'
req = urllib.request.Request(
f'{SUPABASE_URL}/auth/v1/admin/users',
method='POST',
headers={
'Content-Type': 'application/json',
'apikey': SERVICE_KEY,
'Authorization': f'Bearer {SERVICE_KEY}'
},
data=json.dumps({'email': email, 'password': 'VerifyTest123!', 'email_confirm': True}).encode()
)
PYTHON = 'https://opticparse-python-sg.onrender.com'
NODE = 'https://opticparse-1opticparse-node-sg.onrender.com'
try:
res = urllib.request.urlopen(req)
user_id = json.loads(res.read())['id']
req2 = urllib.request.Request(
f'{PYTHON}/gateway/keys/generate',
method='POST',
headers={'Content-Type': 'application/json'},
data=json.dumps({'user_id': user_id}).encode()
)
res2 = urllib.request.urlopen(req2, timeout=30)
api_key = json.loads(res2.read())['api_key']
print(f'βœ… API key generated: {api_key[:20]}...')
with open('verify_key.txt', 'w') as f:
f.write(f'{user_id}|{api_key}')
except Exception as e:
print('❌ API key generation failed:', e)
user_id = ''
api_key = ''
print('\n=== SECTION 4: Test All API Endpoints ===')
def test_endpoint(name, method, url, data=None, headers=None, expected_codes=[200]):
try:
start = time.time()
h = {'Content-Type': 'application/json', 'X-API-Key': api_key}
if headers: h.update(headers)
if headers and 'X-API-Key' in headers and headers['X-API-Key'] is None:
del h['X-API-Key']
req = urllib.request.Request(url, method=method, data=data, headers=h)
res = urllib.request.urlopen(req, timeout=90)
elapsed = time.time() - start
body = res.read().decode()[:200]
status = 'βœ…' if res.status in expected_codes else '⚠️'
print(f'{status} {name}: {res.status} ({elapsed:.1f}s)')
return res.status, body
except urllib.error.HTTPError as e:
elapsed = time.time() - start
body = e.read().decode()[:200]
status = 'βœ…' if e.code in expected_codes else '❌'
print(f'{status} {name}: {e.code} ({elapsed:.1f}s)')
return e.code, body
except Exception as e:
print(f'❌ {name}: {str(e)[:80]}')
return 0, str(e)
if user_id:
test_endpoint('Gateway - Generate Key', 'POST', f'{PYTHON}/gateway/keys/generate', json.dumps({'user_id': user_id}).encode())
test_endpoint('Gateway - Get Usage', 'GET', f'{PYTHON}/gateway/usage/{user_id}')
test_endpoint('Gateway - Regenerate Key', 'POST', f'{PYTHON}/gateway/keys/regenerate', json.dumps({'user_id': user_id}).encode())
test_endpoint('NEW - Usage History (30 days)', 'GET', f'{PYTHON}/gateway/usage/{user_id}/history')
test_endpoint('Vision Scrape (sync)', 'POST', f'{PYTHON}/api/vision-scrape', json.dumps({'target_url': 'https://news.ycombinator.com', 'extraction_query': 'Top 3 post titles', 'response_schema': {'posts': [{'title': 'string'}]}}).encode())
status, body = test_endpoint('NEW - Vision Scrape (async)', 'POST', f'{PYTHON}/api/vision-scrape/async', json.dumps({'target_url': 'https://example.com', 'extraction_query': 'Main heading', 'response_schema': {'heading': 'string'}}).encode())
job_id = None
try: job_id = json.loads(body).get('job_id')
except: pass
time.sleep(3)
if job_id: test_endpoint('NEW - Job Status Check', 'GET', f'{PYTHON}/api/vision-scrape/jobs/{job_id}')
status, body = test_endpoint('Watch - Create', 'POST', f'{PYTHON}/api/watch', json.dumps({'target_url': 'https://example.com', 'extraction_query': 'Monitor changes'}).encode())
watch_id = None
try: watch_id = json.loads(body).get('watch_id') or json.loads(body).get('id')
except: pass
if watch_id: test_endpoint('Watch - Get Diff', 'GET', f'{PYTHON}/api/watch/{watch_id}/diff')
test_endpoint('PhishVision - Single Detect', 'POST', f'{NODE}/api/phish-detect', json.dumps({'url': 'https://google.com'}).encode(), headers={'X-API-Key': None})
test_endpoint('PhishVision - Bulk Scan', 'POST', f'{NODE}/api/phish-batch-simple', json.dumps({'urls': ['https://google.com', 'https://github.com']}).encode(), headers={'X-API-Key': None})
test_endpoint('PhishVision - PDF Report', 'GET', f'{NODE}/api/phish-report?url=https://example.com', headers={'X-API-Key': None}, expected_codes=[200])
test_endpoint('PhishVision - Create Monitor', 'POST', f'{NODE}/api/monitor', json.dumps({'url': 'https://example.com', 'webhook_url': 'https://example.com/webhook'}).encode(), headers={'X-API-Key': None})
test_endpoint('PhishVision - Cache Stats', 'GET', f'{NODE}/api/cache-stats', headers={'X-API-Key': None})
print('\n=== SECTION 8: New Features Verification ===')
if user_id:
try:
req = urllib.request.Request(f'{PYTHON}/gateway/usage/{user_id}/history', headers={'X-API-Key': api_key})
res = urllib.request.urlopen(req, timeout=30)
data = json.loads(res.read())
days = len(data.get('history', []))
print(f'βœ… Usage history: returns {days} days of data')
except Exception as e: print(f'❌ Usage history: {str(e)[:80]}')
try:
req = urllib.request.Request(f'{PYTHON}/api/vision-scrape/async', method='POST', headers={'Content-Type': 'application/json', 'X-API-Key': api_key}, data=json.dumps({'target_url': 'https://example.com', 'extraction_query': 'What is the heading?', 'response_schema': {'heading': 'string'}}).encode())
res = urllib.request.urlopen(req, timeout=30)
data = json.loads(res.read())
job_id = data.get('job_id')
print(f'βœ… Async scrape: job_id={job_id[:8]}... status={data.get("status")}')
print(' Waiting 20s for job to complete...')
time.sleep(20)
req2 = urllib.request.Request(f'{PYTHON}/api/vision-scrape/jobs/{job_id}', headers={'X-API-Key': api_key})
res2 = urllib.request.urlopen(req2, timeout=30)
job_data = json.loads(res2.read())
job_status = job_data.get('status')
if job_status == 'completed': print(f' βœ… Async job completed!')
elif job_status == 'processing': print(f' ⚠️ Still processing (normal for first run)')
else: print(f' ❌ Job failed: {job_data.get("error")}')
except Exception as e: print(f'❌ Async scrape: {str(e)[:80]}')
try:
req = urllib.request.Request(f'{NODE}/api/phish-detect', method='POST', headers={'Content-Type': 'application/json'}, data=json.dumps({'url': 'https://github.com'}).encode())
res = urllib.request.urlopen(req, timeout=90)
data = json.loads(res.read())
required_fields = ['verdict', 'confidence_score_percentage', 'domain_age_days', 'registrar', 'redirect_chain', 'visual_anomalies_detected']
missing = [f for f in required_fields if f not in data]
if not missing: print(f'βœ… PhishVision full JSON: all fields present')
else: print(f'❌ PhishVision missing fields: {missing}')
except Exception as e: print(f'❌ PhishVision full JSON: {str(e)[:80]}')
print('\n=== SECTION 5: Security Tests ===')
try:
req = urllib.request.Request(f'{PYTHON}/api/vision-scrape', method='POST', headers={'Content-Type': 'application/json', 'X-API-Key': 'fake-key-123'}, data=json.dumps({'target_url': 'https://example.com', 'extraction_query': 'test'}).encode())
urllib.request.urlopen(req, timeout=10)
print('❌ Fake key NOT rejected')
except urllib.error.HTTPError as e:
if e.code == 401: print('βœ… Fake key rejected (401)')
else: print(f'⚠️ Fake key got {e.code}')
except Exception as e:
print(f'⚠️ {str(e)[:60]}')
try:
req = urllib.request.Request(f'{NODE}/api/phish-detect', method='POST', headers={'Content-Type': 'application/json'}, data=json.dumps({'url': 'http://127.0.0.1/secret'}).encode())
urllib.request.urlopen(req, timeout=10)
print('❌ Internal URL NOT blocked')
except urllib.error.HTTPError as e:
if e.code in [400, 403]: print(f'βœ… Internal URL blocked ({e.code})')
else: print(f'⚠️ Internal URL got {e.code}')
except Exception as e:
print(f'⚠️ {str(e)[:60]}')
try:
req = urllib.request.Request(f'{PYTHON}/api/vision-scrape', method='POST', headers={'Content-Type': 'application/json', 'X-API-Key': 'wrong-format-key'}, data=json.dumps({'target_url': 'https://example.com', 'extraction_query': 'test'}).encode())
urllib.request.urlopen(req, timeout=10)
print('❌ Wrong format key NOT rejected')
except urllib.error.HTTPError as e:
if e.code == 401: print('βœ… Wrong format key rejected (401)')
else: print(f'⚠️ Wrong format key got {e.code}')
except Exception as e:
print(f'⚠️ {str(e)[:60]}')
try:
req = urllib.request.Request('https://opticparse.com', headers={'User-Agent': 'Mozilla/5.0'})
res = urllib.request.urlopen(req, timeout=15)
print(f'βœ… HTTPS working: {res.status}')
except Exception as e:
print(f'❌ HTTPS: {str(e)[:60]}')
print('\n=== SECTION 6: Database Security ===')
anon_key = ''
try:
with open('dashboard/.env.production') as f:
for line in f:
if 'VITE_SUPABASE_ANON_KEY' in line:
anon_key = line.split('=', 1)[1].strip().strip('"').strip("'")
except: pass
tables = ['users', 'api_keys', 'usage_logs', 'watches', 'monitors']
for table in tables:
try:
req = urllib.request.Request(f'{SUPABASE_URL}/rest/v1/{table}?select=*', headers={'apikey': anon_key, 'Authorization': f'Bearer {anon_key}'})
res = urllib.request.urlopen(req, timeout=10)
data = json.loads(res.read())
if len(data) == 0: print(f'βœ… {table}: RLS enforced')
else: print(f'❌ {table}: BREACH β€” {len(data)} rows exposed')
except: print(f'βœ… {table}: RLS enforced')
print('\n=== SECTION 7: Content Verification ===')
files = {
'docs/index.html': [('No GPT-4o', 'GPT-4o', False), ('WebLLM section', 'WebLLM', True), ('About page link', 'about.html', True), ('Privacy linked', 'privacy', True), ('Terms linked', 'terms', True), ('Dashboard link', 'dashboard.opticparse.com', True), ('LemonSqueezy URL', 'lemonsqueezy.com', True), ('Schema accuracy', 'Schema Accuracy', True), ('No placeholder', 'PLACEHOLDER', False), ('No old URL', 'parastejpal987', False), ('Async feature', 'async', True), ('Bulk scanning', 'Bulk', True)],
'docs/about.html': [('About page exists', 'OpticParse', True), ('Punjab mentioned', 'Punjab', True), ('WebLLM mentioned', 'WebLLM', True), ('Contact email', 'support@opticparse.com', True)],
'docs/privacy.html': [('Contact email', 'support@opticparse.com', True), ('No placeholder email', 'your email', False)],
'docs/terms.html': [('Contact email', 'support@opticparse.com', True), ('No placeholder email', 'your email', False)]
}
for filepath, checks in files.items():
if not os.path.exists(filepath): print(f'❌ {filepath}: FILE NOT FOUND'); continue
content = open(filepath, 'r', encoding='utf-8').read().lower()
for name, term, should_exist in checks:
found = term.lower() in content
print(f'{"βœ…" if (found == should_exist) else "❌"} {name}')
print('\n=== SECTION 8: New Features Verification ===')
if user_id:
try:
req = urllib.request.Request(f'{PYTHON}/gateway/usage/{user_id}/history', headers={'X-API-Key': api_key})
res = urllib.request.urlopen(req, timeout=30)
data = json.loads(res.read())
days = len(data.get('history', []))
print(f'βœ… Usage history: returns {days} days of data')
except Exception as e: print(f'❌ Usage history: {str(e)[:80]}')
try:
req = urllib.request.Request(f'{PYTHON}/api/vision-scrape/async', method='POST', headers={'Content-Type': 'application/json', 'X-API-Key': api_key}, data=json.dumps({'target_url': 'https://example.com', 'extraction_query': 'What is the heading?', 'response_schema': {'heading': 'string'}}).encode())
res = urllib.request.urlopen(req, timeout=30)
data = json.loads(res.read())
job_id = data.get('job_id')
print(f'βœ… Async scrape: job_id={job_id[:8]}... status={data.get("status")}')
print(' Waiting 20s for job to complete...')
time.sleep(20)
req2 = urllib.request.Request(f'{PYTHON}/api/vision-scrape/jobs/{job_id}', headers={'X-API-Key': api_key})
res2 = urllib.request.urlopen(req2, timeout=30)
job_data = json.loads(res2.read())
job_status = job_data.get('status')
if job_status == 'completed': print(f' βœ… Async job completed!')
elif job_status == 'processing': print(f' ⚠️ Still processing (normal for first run)')
else: print(f' ❌ Job failed: {job_data.get("error")}')
except Exception as e: print(f'❌ Async scrape: {str(e)[:80]}')
try:
req = urllib.request.Request(f'{NODE}/api/phish-detect', method='POST', headers={'Content-Type': 'application/json'}, data=json.dumps({'url': 'https://github.com'}).encode())
res = urllib.request.urlopen(req, timeout=90)
data = json.loads(res.read())
required_fields = ['verdict', 'confidence_score_percentage', 'domain_age_days', 'registrar', 'redirect_chain', 'visual_anomalies_detected']
missing = [f for f in required_fields if f not in data]
if not missing: print(f'βœ… PhishVision full JSON: all fields present')
else: print(f'❌ PhishVision missing fields: {missing}')
except Exception as e: print(f'❌ PhishVision full JSON: {str(e)[:80]}')