Ctrl K
ComunidadGuías…

test-token.js

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env node
// API Token Integration Test Script using cosmos-cloud-sdk
// Usage: node test-token.js <base_url> <admin_token> <readonly_token>
// Example: node test-token.js https://localhost cosmos_abc123 cosmos_xyz789
//
// Requires Node.js 18+ (built-in fetch). No external dependencies.
// Accepts self-signed certs.

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

const { createClient } = require('./sdk/dist/index.js');

const [,, baseUrl, adminToken, readonlyToken] = process.argv;

if (!baseUrl || !adminToken || !readonlyToken) {
  console.error('Usage: node test-token.js <base_url> <admin_token> <readonly_token>');
  process.exit(2);
}

// --- Create SDK clients ---

const admin = createClient({ baseUrl, token: adminToken });
const readonly = createClient({ baseUrl, token: readonlyToken });

// Raw request helper (for no-token and invalid-token tests)
async function rawRequest(path, method, token, body) {
  const url = `${baseUrl}${path}`;
  const headers = { 'Content-Type': 'application/json' };
  if (token) headers['Authorization'] = `Bearer ${token}`;
  const opts = { method, headers };
  if (body !== undefined) opts.body = JSON.stringify(body);
  const res = await fetch(url, opts);
  let data = null;
  try { data = await res.json(); } catch { }
  return { status: res.status, data };
}

// --- Test framework ---

let passed = 0;
let failed = 0;

async function test(name, fn) {
  try {
    await fn();
    passed++;
    console.log(`[PASS] ${name}`);
  } catch (err) {
    failed++;
    console.log(`[FAIL] ${name} — ${err.message}`);
  }
}

function expectStatus(res, expected, label) {
  if (res.status !== expected) {
    throw new Error(`${label}: expected ${expected}, got ${res.status}`);
  }
}

// --- Test Groups ---

async function group1_sdkBasicCalls() {
  console.log('\n— Group 1: SDK Basic Calls —');

  await test('admin.getStatus()', async () => {
    const res = await admin.getStatus();
    if (res.status !== 'OK') throw new Error('Expected status OK, got ' + res.status);
  });

  await test('readonly.getStatus()', async () => {
    const res = await readonly.getStatus();
    if (res.status !== 'OK') throw new Error('Expected status OK, got ' + res.status);
  });

  await test('admin.isOnline()', async () => {
    const res = await admin.isOnline();
    if (res.status !== 'OK') throw new Error('Expected status OK');
  });
}

async function group2_sdkReadEndpoints() {
  console.log('\n— Group 2: SDK Read Endpoints —');

  await test('admin.config.get()', async () => {
    const res = await admin.config.get();
    if (res.status !== 'OK') throw new Error('Expected OK');
  });

  await test('readonly.config.get()', async () => {
    const res = await readonly.config.get();
    if (res.status !== 'OK') throw new Error('Expected OK');
  });

  await test('admin.docker.list()', async () => {
    const res = await admin.docker.list();
    if (res.status !== 'OK') throw new Error('Expected OK');
  });

  await test('readonly.docker.list()', async () => {
    const res = await readonly.docker.list();
    if (res.status !== 'OK') throw new Error('Expected OK');
  });

  await test('admin.users.list()', async () => {
    const res = await admin.users.list();
    if (res.status !== 'OK') throw new Error('Expected OK');
  });

  await test('readonly.users.list()', async () => {
    const res = await readonly.users.list();
    if (res.status !== 'OK') throw new Error('Expected OK');
  });

  await test('admin.apiTokens.list()', async () => {
    const res = await admin.apiTokens.list();
    if (res.status !== 'OK') throw new Error('Expected OK');
  });

  await test('readonly.apiTokens.list()', async () => {
    const res = await readonly.apiTokens.list();
    if (res.status !== 'OK') throw new Error('Expected OK');
  });
}

async function group3_sdkWriteEndpoints() {
  console.log('\n— Group 3: SDK Write Endpoints (admin vs read-only) —');

  // admin: create + delete probe token
  let probeCreated = false;
  try {
    await test('admin.apiTokens.create() - probe', async () => {
      const res = await admin.apiTokens.create({ name: '__test_probe__' });
      if (res.status !== 'OK') throw new Error('Expected OK, got ' + res.status);
      probeCreated = true;
    });

    await test('admin.apiTokens.remove() - cleanup probe', async () => {
      const res = await admin.apiTokens.remove('__test_probe__');
      if (res.status !== 'OK') throw new Error('Expected OK');
      probeCreated = false;
    });
  } finally {
    if (probeCreated) {
      try { await admin.apiTokens.remove('__test_probe__'); } catch { }
    }
  }

  // readonly: create should fail
  await test('readonly.apiTokens.create() - denied', async () => {
    try {
      await readonly.apiTokens.create({ name: '__test_probe__' });
      throw new Error('Should have thrown');
    } catch (e) {
      if (!e.code && !e.status) throw e;
      // Expected: error thrown (403)
    }
  });

  // readonly: delete should fail
  await test('readonly.apiTokens.remove() - denied', async () => {
    try {
      await readonly.apiTokens.remove('__test_probe__');
      throw new Error('Should have thrown');
    } catch (e) {
      if (!e.code && !e.status) throw e;
    }
  });

  // admin: idempotent config write-back
  await test('admin.config.set() - idempotent write-back', async () => {
    const getRes = await admin.config.get();
    const config = getRes.data;
    const putRes = await admin.config.set(config);
    if (putRes.status !== 'OK') throw new Error('Expected OK');
  });

  // readonly: config set denied
  await test('readonly.config.set() - denied', async () => {
    try {
      await readonly.config.set({});
      throw new Error('Should have thrown');
    } catch (e) {
      if (!e.code && !e.status) throw e;
    }
  });
}

async function group4_noToken() {
  console.log('\n— Group 4: No-Token Rejection —');

  for (const [path, label] of [
    ['/cosmos/api/config', 'config'],
    ['/cosmos/api/servapps', 'servapps'],
    ['/cosmos/api/users', 'users'],
  ]) {
    await test(`GET ${label} - no token rejected`, async () => {
      expectStatus(await rawRequest(path, 'GET', null), 401, 'no token');
    });
  }
}

async function group5_invalidToken() {
  console.log('\n— Group 5: Invalid Token —');

  await test('status - invalid token rejected', async () => {
    expectStatus(await rawRequest('/cosmos/api/status', 'GET', 'cosmos_invalidtoken'), 401, 'invalid token');
  });
}

// --- Run ---

async function main() {
  console.log(`Testing API tokens via cosmos-cloud-sdk against ${baseUrl}`);
  console.log(`Admin token: ${adminToken.slice(0, 12)}...`);
  console.log(`Readonly token: ${readonlyToken.slice(0, 12)}...`);

  await group1_sdkBasicCalls();
  await group2_sdkReadEndpoints();
  await group3_sdkWriteEndpoints();
  await group4_noToken();
  await group5_invalidToken();

  console.log(`\nResults: ${passed}/${passed + failed} passed`);
  if (failed > 0) {
    console.log(`${failed} test(s) FAILED`);
    process.exit(1);
  }
}

main().catch(err => {
  console.error('Fatal error:', err);
  process.exit(1);
});