feat: initial commit of Ghaymah internal DNS, TCP and security testing suite and report
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
// 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); });
|
||||
Reference in New Issue
Block a user