Volver al inicio

Búsqueda de código híbrida en GitLab en más de 100 proyectos

Script híbrido acelera la búsqueda de cadenas en más de 100 proyectos de GitLab: API Search para código y documentación, recorrido recursivo de configuraciones. Procesamiento paralelo con ThreadPoolExecutor. Código detallado e informes para auditorías técnicas.

Búsqueda rápida en más de 100 repositorios de GitLab: híbrido API+Deep
Advertisement 728x90

Búsqueda Híbrida en Repositorios de GitLab: API y Escaneo Profundo de Configuraciones

A medida que crece el número de proyectos en GitLab, buscar cadenas específicas en código, archivos YAML, JSON y .env se convierte en un desafío. La búsqueda estándar de la interfaz y la API funciona rápidamente para código, pero omite configuraciones. La solución es un script híbrido en Python que usa python-gitlab: Búsqueda por API para código y recorrido recursivo para configuraciones. El tiempo de búsqueda en más de 100 proyectos se redujo a minutos.

Análisis de Enfoques Alternativos

Antes del desarrollo, evaluamos métodos existentes. Ninguno cubría completamente la tarea sin compromisos.

| Enfoque | Ventajas | Desventajas |

Google AdInline article slot

|--------|-------|--------|

| Interfaz de GitLab | Rápido de iniciar | Manual para 100+ proyectos, débil en configuraciones |

| grep/ripgrep local | Control total | Clonar todos los repositorios toma horas |

Google AdInline article slot

| Búsqueda por API de GitLab | Disponible de forma remota | Omite YAML/JSON/env |

| Sourcegraph | Indexación potente | Requiere despliegue de infraestructura |

El rastreador híbrido demostró ser óptimo: aprovecha las fortalezas de la API y añade recorrido para puntos débiles sin dependencias externas.

Google AdInline article slot

Diferencias en la Búsqueda por Tipos de Archivo

GitLab indexa de forma confiable código y documentación, pero las configuraciones a menudo quedan fuera de la búsqueda.

  • Código (.py, .js, .go, .ts): Búsqueda por API — la indexación cubre completamente.
  • Documentación (.md, .txt): Búsqueda por API — velocidad y precisión suficientes.
  • Configuraciones (.yml, .yaml, .json, .env): Búsqueda Profunda — árbol recursivo + obtención de contenido.
  • Archivos binarios: Excluidos para ahorrar recursos.

Lógica: delegar tareas a la herramienta para tipos fuertes, manejar manualmente los débiles.

Arquitectura del Script

El script sigue una canalización:

  • Obtener lista de proyectos en un grupo con subgrupos.
  • Filtrar los archivados e inactivos.
  • Procesamiento paralelo: Búsqueda por API + Búsqueda Profunda.
  • Agregar resultados.
  • Generar informes.
Grupo de GitLab → projects.list() → filtrar activos
↓
Paralelo: Búsqueda por API (código) + Búsqueda Profunda (configuraciones)
↓
Fusionar → Informe detallado + Resumen + Errores

La búsqueda se limita a la rama master para configuraciones actuales. Extender a todas las ramas es posible pero aumenta el tiempo.

Implementación de Componentes Clave

Obtención de Proyectos

group = gl.groups.get(GROUP_ID)
all_projects = group.projects.list(include_subgroups=True, all=True)

Filtrar por estado archived=false y last_activity.

Búsqueda por API para Código

def api_search(gl, project_id, search_terms):
    results = {term: [] for term in search_terms}
    for term in search_terms:
        blobs = gl.search('blobs', term, project_id=project_id)
        for blob in blobs:
            file_path = blob.get('path', '')
            file_ext = os.path.splitext(file_path)[1].lower()
            if file_ext in CODE_EXTENSIONS or file_ext == '':
                results[term].append({
                    'path': file_path,
                    'url': blob.get('web_url', '#'),
                    'found_by': 'API'
                })
    return results

Procesa blobs por extensiones de código.

Búsqueda Profunda para Configuraciones

def deep_search_configs(gl, project_id, search_terms):
    results = {term: [] for term in search_terms}
    project = gl.projects.get(project_id)
    files = project.repository_tree(recursive=True, ref='master')
    for file in files:
        if file['type'] != 'blob':
            continue
        ext = os.path.splitext(file['name'])[1].lower()
        if ext not in CONFIG_EXTENSIONS:
            continue
        content = project.files.get(file_path=file['path'], ref='master').decode()
        content_lower = content.lower()
        for term in search_terms:
            if term.lower() in content_lower:
                results[term].append({
                    'path': file['path'],
                    'found_by': 'Deep'
                })
    return results

Árbol recursivo, obtener contenido, búsqueda de cadenas.

Paralelización del Procesamiento

ThreadPoolExecutor con 3 trabajadores acelera para 100+ proyectos:

with ThreadPoolExecutor(max_workers=3) as executor:
    futures = {executor.submit(process_one_project, gl, p): p for p in active_projects}
    for future in as_completed(futures):
        result = future.result()
        results_list.append(result)

Reduce el tiempo de horas a minutos sin problemas de GIL en tareas vinculadas a E/S.

Formatos de Informe

Detallado: Proyecto, ruta, término, línea, método de búsqueda.

Ejemplo:

PROYECTO: service-a
Ruta: backend/service-a
'SERVICE_EXAMPLE': 2 ocurrencias
  - deploy/prod/values.yml:42 [Profundo]
    Línea 42: SERVICE_EXAMPLE: "{{ .Values.secrets.apiKey }}"

Resumen: Número de proyectos, ocurrencias, API vs Profundo.

Factores de Velocidad

  • Excluir archivos/proyectos innecesarios.
  • API para el 80% de los casos (código).
  • Paralelismo.
  • Enfoque en master.

Limitaciones

  • Solo master.
  • Sin expresiones regulares.
  • Sin deduplicación.
  • Salida por consola.

Puntos Clave

  • El enfoque híbrido minimiza las debilidades de la Búsqueda de GitLab para configuraciones.
  • Paralelismo con 3 hilos es óptimo para límites de tasa de la API.
  • Filtrar proyectos reduce la carga en un 30–50%.
  • La Búsqueda Profunda es precisa para YAML/JSON/env.
  • Adecuado para verificaciones puntuales sin infraestructura.

— Editorial Team

Advertisement 728x90

Leer después