rowboat/GITHUB_COPILOT_E2E_TESTING.md
Rowboat Developer e1e6fa92e8 docs: Add comprehensive end-to-end testing guide for GitHub Copilot
- Add step-by-step testing procedures for all components
- Include manual Device Flow authentication testing
- Add LLM provider testing examples
- Include token storage and refresh verification
- Add model discovery and disconnection tests
- Provide troubleshooting guide
- Add security notes and best practices
2026-04-17 09:23:21 -05:00

7.7 KiB
Raw Blame History

GitHub Copilot Integration - End-to-End Testing Guide

Este documento describe cómo realizar pruebas end-to-end completas de la integración de GitHub Copilot en Rowboat.

Requisitos Previos

  • Rowboat compilado y funcionando (npm run deps sin errores)
  • Cuenta de GitHub activa
  • Acceso a GitHub Copilot (Student, Pro, o Enterprise)

Test 1: Verificar Compilación

cd /home/wilber/rowboat/apps/x

# Compilar todas las dependencias
npm run deps

# Verificar que no hay errores de TypeScript
npm run lint

# Expected output:
# ✓ shared compiled successfully
# ✓ core compiled successfully
# ✓ preload compiled successfully

Test 2: Verificar Tests Unitarios

# Ejecutar tests de GitHub Copilot
npm test -- github-copilot.test.ts

# Expected output:
# ✓ GitHub Copilot Device Flow
#   ✓ requestDeviceCode
#   ✓ pollForToken
#   ✓ startGitHubCopilotAuth
#   ✓ OAuthTokens validation
# ✓ GitHub Copilot Models
#   ✓ Model availability
#   ✓ Model constants
# 
# Tests: 25+ passed

Test 3: Device Flow Authentication (Manual)

Paso 1: Crear un script de prueba

Crea /tmp/test-github-copilot-auth.ts:

import container from '@x/core/di/container';
import { startGitHubCopilotAuthentication, isGitHubCopilotAuthenticated, getGitHubCopilotAuthStatus } from '@x/core/auth/github-copilot-auth';

async function testAuth() {
  console.log('Starting GitHub Copilot authentication test...\n');

  // Paso 1: Iniciar autenticación
  console.log('1⃣ Iniciando Device Flow...');
  const { userCode, verificationUri, tokenPromise } = await startGitHubCopilotAuthentication();
  
  console.log(`\n📱 Código de dispositivo: ${userCode}`);
  console.log(`🔗 Visita: ${verificationUri}`);
  console.log('\n⏳ Esperando autorización... (timeout en 15 minutos)\n');

  try {
    // Paso 2: Esperar autenticación
    await tokenPromise;
    console.log('✅ ¡Autenticado exitosamente!\n');

    // Paso 3: Verificar estado
    const authenticated = await isGitHubCopilotAuthenticated();
    console.log(`2⃣ ¿Autenticado? ${authenticated ? '✅ Sí' : '❌ No'}`);

    const status = await getGitHubCopilotAuthStatus();
    console.log(`3⃣ Estado:`, JSON.stringify(status, null, 2));

    console.log('\n✨ Test completo exitosamente');
  } catch (error) {
    console.error('\n❌ Error:', error);
    process.exit(1);
  }
}

testAuth();

Paso 2: Ejecutar el test

cd /home/wilber/rowboat/apps/x
npx ts-node /tmp/test-github-copilot-auth.ts

# Expected output:
# 1⃣ Iniciando Device Flow...
# 
# 📱 Código de dispositivo: ABCD-1234
# 🔗 Visita: https://github.com/login/device
# 
# ⏳ Esperando autorización... (timeout en 15 minutos)
# 
# (Usuario visita GitHub, ingresa código ABCD-1234)
# 
# ✅ ¡Autenticado exitosamente!
# 
# 2⃣ ¿Autenticado? ✅ Sí
# 3⃣ Estado: {
#   "authenticated": true,
#   "expiresAt": 1234567890
# }
# 
# ✨ Test completo exitosamente

Test 4: Crear proveedor LLM

import { createProvider } from '@x/core/models/models';
import { generateText } from 'ai';

async function testLLM() {
  console.log('Testing GitHub Copilot LLM...\n');

  // Crear proveedor
  console.log('1⃣ Creando proveedor GitHub Copilot...');
  const config = {
    flavor: 'github-copilot' as const,
  };
  const provider = await createProvider(config);
  console.log('✅ Proveedor creado\n');

  // Crear modelo
  console.log('2⃣ Creando modelo gpt-4o...');
  const model = provider.languageModel('gpt-4o');
  console.log('✅ Modelo creado\n');

  // Generar texto
  console.log('3⃣ Enviando prompt a GitHub Copilot...');
  const response = await generateText({
    model,
    prompt: 'Say hello in Spanish',
  });
  console.log('✅ Respuesta recibida:\n');
  console.log(response.text);
}

testLLM();

Test 5: Verificar Almacenamiento de Tokens

# Ver tokens guardados
cat ~/.rowboat/config/oauth.json | jq '.providers."github-copilot"'

# Expected output:
# {
#   "tokens": {
#     "access_token": "ghu_...",
#     "refresh_token": null,
#     "expires_at": 1234567890,
#     "token_type": "Bearer",
#     "scopes": ["read:user", "user:email", "gist"]
#   },
#   "clientId": "Iv1.b507a08c87ecfe98"
# }

Test 6: Probar Refresh de Tokens

import { getGitHubCopilotAccessToken } from '@x/core/auth/github-copilot-auth';
import * as oauthClient from '@x/core/auth/oauth-client';

async function testTokenRefresh() {
  console.log('Testing token refresh...\n');

  // Obtener token actual
  console.log('1⃣ Obteniendo token de acceso...');
  const token = await getGitHubCopilotAccessToken();
  console.log(`✅ Token: ${token.substring(0, 20)}...\n`);

  // Verificar expiración
  console.log('2⃣ Verificando expiración...');
  const connection = await container.resolve('oauthRepo').read('github-copilot');
  if (connection.tokens) {
    const expiresIn = connection.tokens.expires_at - Math.floor(Date.now() / 1000);
    console.log(`✅ Token expira en: ${expiresIn} segundos`);
    if (expiresIn > 3600) {
      console.log('   (Aún es válido por más de 1 hora)\n');
    }
  }
}

testTokenRefresh();

Test 7: Listar Modelos Disponibles

import { getAvailableGitHubCopilotModels } from '@x/core/auth/github-copilot-models';

async function testModels() {
  console.log('Modelos disponibles en GitHub Copilot:\n');
  
  const models = await getAvailableGitHubCopilotModels();
  models.forEach((model, i) => {
    console.log(`${i + 1}. ${model}`);
  });
}

testModels();

Test 8: Desconectar GitHub Copilot

import { disconnectGitHubCopilot, isGitHubCopilotAuthenticated } from '@x/core/auth/github-copilot-auth';

async function testDisconnect() {
  console.log('Desconectando GitHub Copilot...\n');

  console.log('1⃣ Estado antes: ', await isGitHubCopilotAuthenticated());
  
  await disconnectGitHubCopilot();
  
  console.log('2⃣ Estado después: ', await isGitHubCopilotAuthenticated());
  
  console.log('\n✅ Desconectado correctamente');
}

testDisconnect();

Verificación de Checklist

  • Compilación exitosa sin errores TypeScript
  • Tests unitarios pasan (25+ casos)
  • Device Flow funciona y abre el navegador
  • Usuario puede completar autenticación en GitHub
  • Tokens se guardan en ~/.rowboat/config/oauth.json
  • Proveedor LLM se crea correctamente
  • Modelo responde a prompts
  • Token se actualiza automáticamente si expira
  • Tokens se eliminan al desconectar
  • Modelos disponibles se listan correctamente

Troubleshooting

Error: "GitHub Copilot not authenticated"

  • Ejecutar Device Flow nuevamente: startGitHubCopilotAuthentication()
  • Verificar que tokens existen: cat ~/.rowboat/config/oauth.json

Error: "Token expired"

  • El sistema debería intentar refresh automático
  • Si falla, ejecutar Device Flow nuevamente

Error: "Cannot reach API"

  • Verificar conexión a internet
  • Verificar que https://models.github.com/api/openai/ es accesible
  • Verificar que token es válido: npm run test -- github-copilot

Error: "Model not found"

  • Verificar que el modelo está disponible en tu plan
  • Usar gpt-4o como fallback

Recursos Adicionales

Notas de Seguridad

  • Nunca compartas tu código de dispositivo
  • Los tokens se almacenan en ~/.rowboat/config/oauth.json - asegúrate de que los permisos son correctos
  • Desconecta cuando no uses GitHub Copilot
  • Los tokens expiran automáticamente (generalmente en 8 horas)