mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-29 10:26:23 +02:00
- 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
280 lines
7.7 KiB
Markdown
280 lines
7.7 KiB
Markdown
# 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)
|