// Phase 3 & 4: Complete DNS, TCP, Security, and Isolation Tests on Ghaymah // This runs AFTER apps are deployed and accessible const APP_A_ID = 'af1b9e91-9bec-4d6a-b76c-92d7273b82ce'; const APP_B_ID = 'fcbd895c-2370-46db-bd6a-057f6d887b0f'; const PROJECT_ID = '3f55ceef-78ae-40c8-a41b-0505db8c59ee'; const fs = require('fs'); let report = []; function log(phase, msg, data) { const ts = new Date().toISOString(); const line = `[${ts}] [${phase}] ${msg}`; console.log(line); if (data) console.log(JSON.stringify(data, null, 2)); report.push({ ts, phase, msg, data }); } async function auth() { const res = await fetch('https://auth.ghaymah.systems/signin/email-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'ziadalex2003@gmail.com', password: '2062003Mz*' }) }); const data = await res.json(); return { token: data.session.accessToken, userId: data.session.user.id }; } async function gql(token, query, variables = {}) { const res = await fetch('https://graphql.ghaymah.systems/v1/graphql', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, body: JSON.stringify({ query, variables }) }); return res.json(); } async function appRequest(domain, path, timeout = 8000) { try { const res = await fetch(`https://${domain}${path}`, { signal: AbortSignal.timeout(timeout) }); return await res.json(); } catch (e) { return { _error: e.message }; } } async function main() { const { token, userId } = await auth(); log('AUTH', 'Authenticated', { userId }); // Step 1: Get app domains and status log('RECON', 'Fetching app resources...'); const resData = await gql(token, `query GetResources($userId: uuid) { ghaymah_cloud_resources(where: { user_id: { _eq: $userId }, deleted: { _eq: false }, chart_name: { _eq: "ghaymah-app" } }) { id chart_name status values message } }`, { userId }); const apps = resData.data?.ghaymah_cloud_resources || []; const appA = apps.find(a => a.values?.name === 'tcp-echo-server'); const appB = apps.find(a => a.values?.name === 'tcp-test-client'); const authDeploy = apps.find(a => a.values?.name === 'auth-deploy'); const domainA = appA?.values?.publicAccess?.domain; const domainB = appB?.values?.publicAccess?.domain; const domainAuth = authDeploy?.values?.publicAccess?.domain; log('RECON', 'App A (tcp-echo-server)', { status: appA?.status, domain: domainA, project: appA?.values?.projectId }); log('RECON', 'App B (tcp-test-client)', { status: appB?.status, domain: domainB, project: appB?.values?.projectId }); log('RECON', 'App auth-deploy (different project)', { status: authDeploy?.status, domain: domainAuth, project: authDeploy?.values?.projectId }); if (!domainA || !domainB) { log('ERROR', 'Missing domains! Cannot proceed with tests.'); // Try ListApps mutation to get hostnames const listApps = await gql(token, `mutation ListApps { listApps { id name status alias ports { name number hostname } } }`); log('RECON', 'ListApps result', listApps.data?.listApps); // Save partial report and exit fs.writeFileSync('D:/cumin/ghaymah_dns_net_sec_tests/logs/06_test_results.json', JSON.stringify(report, null, 2)); return; } // ═══════════════════════════════════════════════ // PHASE 3: FUNCTIONALITY & QA TESTING // ═══════════════════════════════════════════════ log('PHASE3', '═══ PHASE 3: FUNCTIONALITY & QA TESTING ═══'); // 3.1: Health checks log('PHASE3', 'Testing App A health...'); const healthA = await appRequest(domainA, '/health'); log('PHASE3', 'App A health response', healthA); log('PHASE3', 'Testing App B health...'); const healthB = await appRequest(domainB, '/health'); log('PHASE3', 'App B health response', healthB); // 3.2: DNS Infrastructure log('PHASE3-DNS', '--- Internal DNS Verification ---'); // Get resolv.conf from both apps const resolvA = await appRequest(domainA, '/resolv-conf'); log('PHASE3-DNS', 'App A resolv.conf', resolvA); const resolvB = await appRequest(domainB, '/resolv-conf'); log('PHASE3-DNS', 'App B resolv.conf', resolvB); // Get IP addresses from both apps const ipA = await appRequest(domainA, '/ip-addr'); log('PHASE3-DNS', 'App A network interfaces', ipA); const ipB = await appRequest(domainB, '/ip-addr'); log('PHASE3-DNS', 'App B network interfaces', ipB); // DNS Lookup tests from App B -> App A const dnsPatterns = [ 'tcp-echo-server', 'tcp-echo-server.mesh', 'tcp-echo-server.dns-tcp-test.mesh', 'tcp-echo-server.local', 'tcp-echo-server.dns-tcp-test', 'tcp-echo-server.internal', 'tcp-echo-server.svc.cluster.local', ]; log('PHASE3-DNS', 'Testing DNS resolution patterns from App B -> App A...'); for (const pattern of dnsPatterns) { const dnsResult = await appRequest(domainB, `/dns-lookup?name=${encodeURIComponent(pattern)}`); log('PHASE3-DNS', `DNS lookup: ${pattern}`, dnsResult); } // DNS Lookup tests from App A -> App B const dnsPatternsB = [ 'tcp-test-client', 'tcp-test-client.mesh', 'tcp-test-client.dns-tcp-test.mesh', 'tcp-test-client.local', 'tcp-test-client.dns-tcp-test', ]; log('PHASE3-DNS', 'Testing DNS resolution patterns from App A -> App B...'); for (const pattern of dnsPatternsB) { const dnsResult = await appRequest(domainA, `/dns-lookup?name=${encodeURIComponent(pattern)}`); log('PHASE3-DNS', `DNS lookup: ${pattern}`, dnsResult); } // 3.3: TCP Connection Tests log('PHASE3-TCP', '--- TCP Connection Tests ---'); // Extract WireGuard/mesh IPs from App A let appAPrivateIp = null; if (ipA?.interfaces) { for (const [name, addrs] of Object.entries(ipA.interfaces)) { if (name === 'wg0' || name.startsWith('wg')) { const v4 = addrs.find(a => a.family === 'IPv4'); if (v4) appAPrivateIp = v4.address; } } if (!appAPrivateIp) { // Try eth0 for (const [name, addrs] of Object.entries(ipA.interfaces)) { if (name === 'eth0') { const v4 = addrs.find(a => a.family === 'IPv4'); if (v4) appAPrivateIp = v4.address; } } } } log('PHASE3-TCP', `App A private IP: ${appAPrivateIp}`); // TCP connect from App B to App A on port 9000 using IP if (appAPrivateIp) { const tcpByIp = await appRequest(domainB, `/tcp-connect?host=${appAPrivateIp}&port=9000`); log('PHASE3-TCP', `TCP via IP (${appAPrivateIp}:9000)`, tcpByIp); } // TCP connect from App B to App A via DNS name for (const dnsName of ['tcp-echo-server', 'tcp-echo-server.mesh']) { const tcpByDns = await appRequest(domainB, `/tcp-connect?host=${dnsName}&port=9000`); log('PHASE3-TCP', `TCP via DNS (${dnsName}:9000)`, tcpByDns); } // HTTP connectivity test (App B -> App A port 8080) if (appAPrivateIp) { const httpByIp = await appRequest(domainB, `/tcp-connect?host=${appAPrivateIp}&port=8080`); log('PHASE3-TCP', `HTTP port via IP (${appAPrivateIp}:8080)`, httpByIp); } // ═══════════════════════════════════════════════ // PHASE 4: SECURITY & SCOPING // ═══════════════════════════════════════════════ log('PHASE4', '═══ PHASE 4: SECURITY & SCOPING ═══'); // 4.1: Isolation & Lateral Movement log('PHASE4-ISO', '--- Isolation & Lateral Movement Tests ---'); // Try to reach auth-deploy (DIFFERENT project) if (domainAuth) { // DNS lookup for cross-project app const crossProjectPatterns = [ 'auth-deploy', 'auth-deploy.mesh', 'auth-deploy.auth-deploy.mesh', ]; for (const pattern of crossProjectPatterns) { const crossDns = await appRequest(domainB, `/dns-lookup?name=${encodeURIComponent(pattern)}`); log('PHASE4-ISO', `Cross-project DNS: ${pattern}`, crossDns); } } // Try to reach scanner-clean (DIFFERENT project, in backoff) const crossPatterns2 = [ 'scanner-clean', 'scanner-clean.mesh', ]; for (const pattern of crossPatterns2) { const crossDns = await appRequest(domainB, `/dns-lookup?name=${encodeURIComponent(pattern)}`); log('PHASE4-ISO', `Cross-project DNS (scanner-clean): ${pattern}`, crossDns); } // 4.2: Network Enumeration (Port Scan) log('PHASE4-SCAN', '--- Network Enumeration ---'); if (appAPrivateIp) { const scanA = await appRequest(domainB, `/port-scan?host=${appAPrivateIp}&ports=22,53,80,443,3000,4000,5432,6379,8080,9000`, 15000); log('PHASE4-SCAN', `Port scan App A (${appAPrivateIp})`, scanA); } // Scan common internal gateway IPs const internalIps = ['10.100.0.1', '10.100.0.2', '172.26.64.1', '127.0.0.1']; for (const ip of internalIps) { const scanGw = await appRequest(domainB, `/port-scan?host=${ip}&ports=22,53,80,443,8080,9090`, 12000); log('PHASE4-SCAN', `Port scan ${ip}`, scanGw); } // 4.3: External Internet Access & DNS Leak log('PHASE4-LEAK', '--- Dual Routing & DNS Leaks ---'); const extA = await appRequest(domainA, '/external-test'); log('PHASE4-LEAK', 'App A external internet access', extA); const extB = await appRequest(domainB, '/external-test'); log('PHASE4-LEAK', 'App B external internet access', extB); // DNS leak test: resolve external domains const externalDns = ['google.com', 'github.com', 'cloudflare.com']; for (const name of externalDns) { const dnsExt = await appRequest(domainB, `/dns-lookup?name=${encodeURIComponent(name)}`); log('PHASE4-LEAK', `External DNS resolution: ${name}`, dnsExt); } // Save full results fs.writeFileSync('D:/cumin/ghaymah_dns_net_sec_tests/logs/06_test_results.json', JSON.stringify(report, null, 2)); log('DONE', 'All tests completed. Results saved.'); } main().catch(e => { console.error('FATAL:', e); process.exit(1); });