// Comprehensive Ghaymah Platform Test Script // Tests: Project creation, App deployment, DNS resolution, TCP, and Security 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 gwApi(path, token, opts = {}) { const res = await fetch(`https://gateway.ghaymah.systems${path}`, { ...opts, headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token, ...(opts.headers || {}) } }); return res.json(); } function log(phase, msg) { const ts = new Date().toISOString(); console.log(`[${ts}] [${phase}] ${msg}`); } async function main() { log('AUTH', 'Authenticating...'); const { token, userId } = await auth(); log('AUTH', `Authenticated as ${userId}`); // 1. List current resources log('RECON', 'Listing existing resources...'); const resources = await gql(token, `query GetResources($userId: uuid) { ghaymah_cloud_resources(where: { user_id: { _eq: $userId }, deleted: { _eq: false } }) { id chart_name chart_version status values } }`, { userId }); const resList = resources.data?.ghaymah_cloud_resources || []; resList.forEach(r => log('RECON', ` Resource: ${r.chart_name} | ${r.values?.name || r.id} | status: ${r.status}`)); // 2. List existing apps via ListApps mutation log('RECON', 'Listing existing apps...'); const apps = await gql(token, `mutation ListApps { listApps { id name image status alias url ports { name number hostname health { path } } env { name value } tags { key value } } }`); const appList = apps.data?.listApps || []; appList.forEach(a => log('RECON', ` App: ${a.name} | status: ${a.status} | alias: ${a.alias}`)); log('RECON', ` Total apps: ${appList.length}`); // List full details of the apps appList.forEach(a => { log('RECON', ` App ${a.name} ports: ${JSON.stringify(a.ports)}`); log('RECON', ` App ${a.name} tags: ${JSON.stringify(a.tags)}`); log('RECON', ` App ${a.name} env: ${JSON.stringify(a.env?.map(e => e.name))}`); }); // 3. Create a test project for DNS/TCP testing log('SETUP', 'Creating test project: dns-tcp-test...'); const projectId = crypto.randomUUID(); const createProject = await gql(token, `mutation CreateResourceWithId($id: uuid!, $userId: uuid!, $chartName: String!, $chartVersion: String!, $values: json!) { insert_ghaymah_cloud_resources_one(object: { id: $id, user_id: $userId, chart_name: $chartName, chart_version: $chartVersion, values: $values }) { id } }`, { id: projectId, userId, chartName: 'ghaymah-project', chartVersion: '0.0', values: { name: 'dns-tcp-test', userId } }); log('SETUP', `Project creation result: ${JSON.stringify(createProject)}`); // Wait for project to sync log('SETUP', 'Waiting 10s for project sync...'); await new Promise(r => setTimeout(r, 10000)); // 4. Deploy App A (TCP echo server) log('DEPLOY', 'Creating App A (tcp-echo-server)...'); const appAId = crypto.randomUUID(); const createAppA = await gql(token, `mutation CreateResourceWithId($id: uuid!, $userId: uuid!, $chartName: String!, $chartVersion: String!, $values: json!) { insert_ghaymah_cloud_resources_one(object: { id: $id, user_id: $userId, chart_name: $chartName, chart_version: $chartVersion, values: $values }) { id } }`, { id: appAId, userId, chartName: 'ghaymah-app', chartVersion: '0.1', values: { name: 'tcp-echo-server', projectId, container: { image: 'node:22-alpine' }, resourceTier: 't1', ports: [{ number: 9000, expose: true }], publicAccess: { enabled: true }, source: { enabled: false }, command: ['node', '-e', ` const net = require('net'); const http = require('http'); const dns = require('dns'); const os = require('os'); // TCP Echo Server on port 9000 const tcpServer = net.createServer(socket => { console.log('TCP connection from', socket.remoteAddress); socket.on('data', data => { console.log('TCP received:', data.toString()); socket.write('ECHO:' + data.toString()); }); socket.on('error', () => {}); }); tcpServer.listen(9000, () => console.log('TCP echo server on 9000')); // HTTP Server on port 8080 for health + diagnostics http.createServer(async (req, res) => { const url = new URL(req.url, 'http://localhost'); res.setHeader('Content-Type', 'application/json'); if (url.pathname === '/health' || url.pathname === '/') { res.end(JSON.stringify({ status: 'ok', service: 'tcp-echo-server', hostname: os.hostname() })); } else if (url.pathname === '/dns-lookup') { const name = url.searchParams.get('name'); if (!name) { res.end(JSON.stringify({ error: 'need ?name=' })); return; } try { const addrs = await dns.promises.resolve4(name); res.end(JSON.stringify({ name, addresses: addrs })); } catch(e) { res.end(JSON.stringify({ name, error: e.code || e.message })); } } else if (url.pathname === '/resolv-conf') { const fs = require('fs'); try { const rc = fs.readFileSync('/etc/resolv.conf', 'utf8'); res.end(JSON.stringify({ resolv_conf: rc })); } catch(e) { res.end(JSON.stringify({ error: e.message })); } } else if (url.pathname === '/ip-addr') { const ifaces = os.networkInterfaces(); res.end(JSON.stringify({ interfaces: ifaces })); } else if (url.pathname === '/tcp-connect') { const host = url.searchParams.get('host'); const port = parseInt(url.searchParams.get('port')); if (!host || !port) { res.end(JSON.stringify({ error: 'need ?host=&port=' })); return; } const sock = new net.Socket(); sock.setTimeout(5000); sock.connect(port, host, () => { sock.write('HELLO_FROM_APP_A'); sock.on('data', d => { res.end(JSON.stringify({ success: true, host, port, response: d.toString() })); sock.destroy(); }); }); sock.on('error', e => { res.end(JSON.stringify({ success: false, host, port, error: e.message })); }); sock.on('timeout', () => { res.end(JSON.stringify({ success: false, host, port, error: 'timeout' })); sock.destroy(); }); } else if (url.pathname === '/external-test') { try { const r = await fetch('https://httpbin.org/ip', { signal: AbortSignal.timeout(5000) }); const d = await r.json(); res.end(JSON.stringify({ external_access: true, data: d })); } catch(e) { res.end(JSON.stringify({ external_access: false, error: e.message })); } } else { res.end(JSON.stringify({ error: 'not found' })); } }).listen(8080, () => console.log('HTTP diagnostics on 8080')); `] } }); log('DEPLOY', `App A result: ${JSON.stringify(createAppA)}`); // 5. Deploy App B (tcp-test-client) log('DEPLOY', 'Creating App B (tcp-test-client)...'); const appBId = crypto.randomUUID(); const createAppB = await gql(token, `mutation CreateResourceWithId($id: uuid!, $userId: uuid!, $chartName: String!, $chartVersion: String!, $values: json!) { insert_ghaymah_cloud_resources_one(object: { id: $id, user_id: $userId, chart_name: $chartName, chart_version: $chartVersion, values: $values }) { id } }`, { id: appBId, userId, chartName: 'ghaymah-app', chartVersion: '0.1', values: { name: 'tcp-test-client', projectId, container: { image: 'node:22-alpine' }, resourceTier: 't1', ports: [{ number: 8080, expose: true }], publicAccess: { enabled: true }, source: { enabled: false }, command: ['node', '-e', ` const net = require('net'); const http = require('http'); const dns = require('dns'); const os = require('os'); http.createServer(async (req, res) => { const url = new URL(req.url, 'http://localhost'); res.setHeader('Content-Type', 'application/json'); if (url.pathname === '/health' || url.pathname === '/') { res.end(JSON.stringify({ status: 'ok', service: 'tcp-test-client', hostname: os.hostname() })); } else if (url.pathname === '/dns-lookup') { const name = url.searchParams.get('name'); if (!name) { res.end(JSON.stringify({ error: 'need ?name=' })); return; } try { const addrs = await dns.promises.resolve4(name); res.end(JSON.stringify({ name, addresses: addrs, source: 'resolve4' })); } catch(e) { try { const result = await dns.promises.lookup(name); res.end(JSON.stringify({ name, address: result.address, family: result.family, source: 'lookup' })); } catch(e2) { res.end(JSON.stringify({ name, error: e.code || e.message, error2: e2.code || e2.message })); } } } else if (url.pathname === '/resolv-conf') { const fs = require('fs'); try { const rc = fs.readFileSync('/etc/resolv.conf', 'utf8'); res.end(JSON.stringify({ resolv_conf: rc })); } catch(e) { res.end(JSON.stringify({ error: e.message })); } } else if (url.pathname === '/ip-addr') { const ifaces = os.networkInterfaces(); res.end(JSON.stringify({ interfaces: ifaces })); } else if (url.pathname === '/tcp-connect') { const host = url.searchParams.get('host'); const port = parseInt(url.searchParams.get('port')); if (!host || !port) { res.end(JSON.stringify({ error: 'need ?host=&port=' })); return; } const sock = new net.Socket(); sock.setTimeout(5000); sock.connect(port, host, () => { sock.write('HELLO_FROM_APP_B'); sock.on('data', d => { res.end(JSON.stringify({ success: true, host, port, response: d.toString() })); sock.destroy(); }); }); sock.on('error', e => { res.end(JSON.stringify({ success: false, host, port, error: e.message })); }); sock.on('timeout', () => { res.end(JSON.stringify({ success: false, host, port, error: 'timeout' })); sock.destroy(); }); } else if (url.pathname === '/external-test') { try { const r = await fetch('https://httpbin.org/ip', { signal: AbortSignal.timeout(5000) }); const d = await r.json(); res.end(JSON.stringify({ external_access: true, data: d })); } catch(e) { res.end(JSON.stringify({ external_access: false, error: e.message })); } } else if (url.pathname === '/port-scan') { const host = url.searchParams.get('host'); const portsStr = url.searchParams.get('ports') || '22,53,80,443,3000,4000,5432,6379,8080,9000'; const ports = portsStr.split(',').map(Number); const results = []; for (const p of ports) { try { await new Promise((resolve, reject) => { const s = new net.Socket(); s.setTimeout(2000); s.connect(p, host, () => { results.push({ port: p, status: 'open' }); s.destroy(); resolve(); }); s.on('error', e => { results.push({ port: p, status: 'closed', error: e.code }); resolve(); }); s.on('timeout', () => { results.push({ port: p, status: 'filtered' }); s.destroy(); resolve(); }); }); } catch(e) { results.push({ port: p, status: 'error', error: e.message }); } } res.end(JSON.stringify({ host, scan: results })); } else { res.end(JSON.stringify({ error: 'not found' })); } }).listen(8080, () => console.log('TCP test client HTTP on 8080')); `] } }); log('DEPLOY', `App B result: ${JSON.stringify(createAppB)}`); // Save IDs for later console.log('\n=== DEPLOYMENT IDS ==='); console.log('Project ID:', projectId); console.log('App A (tcp-echo-server) ID:', appAId); console.log('App B (tcp-test-client) ID:', appBId); } main().catch(e => { console.error('FATAL:', e); process.exit(1); });