diff --git a/GITHUB_COPILOT_E2E_TESTING.md b/GITHUB_COPILOT_E2E_TESTING.md new file mode 100644 index 00000000..1a6a9431 --- /dev/null +++ b/GITHUB_COPILOT_E2E_TESTING.md @@ -0,0 +1,280 @@ +# 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 + +```bash +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 + +```bash +# 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`: + +```typescript +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 + +```bash +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 + +```typescript +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 + +```bash +# 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 + +```typescript +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 + +```typescript +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 + +```typescript +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 + +- [GITHUB_COPILOT_INTEGRATION.md](./GITHUB_COPILOT_INTEGRATION.md) - Documentación técnica completa +- [RFC 8628](https://tools.ietf.org/html/rfc8628) - Device Flow OAuth spec +- [GitHub Copilot Docs](https://docs.github.com/en/copilot) - Documentación oficial + +## 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)