diff --git a/bash/functions/pipelines/audit_registry_paths.md b/bash/functions/pipelines/audit_registry_paths.md new file mode 100644 index 00000000..826632be --- /dev/null +++ b/bash/functions/pipelines/audit_registry_paths.md @@ -0,0 +1,67 @@ +--- +name: audit_registry_paths +kind: pipeline +lang: bash +domain: pipelines +version: "1.0.0" +purity: impure +signature: "audit_registry_paths([output_file: string]) -> void" +description: "Audita file_path de todas las functions y types en registry.db, verifica que cada ruta apunte a un archivo existente en disco, y genera un txt con las rutas rotas para que agentes puedan corregirlas." +tags: [registry, audit, validation, paths, launcher, pipeline, bash] +uses_functions: + - assert_command_exists_bash_shell + - assert_file_exists_bash_shell + - validate_registry_paths_bash_shell + - report_execution_json_bash_shell + - exit_with_status_bash_shell +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/pipelines/audit_registry_paths.sh" +--- + +## Ejemplo + +```bash +# Con default (genera broken_paths.txt en la raiz) +./bash/functions/pipelines/audit_registry_paths.sh + +# Con ruta personalizada +./bash/functions/pipelines/audit_registry_paths.sh /tmp/broken.txt + +# Desde fn run (pipeline launcher) +fn run audit_registry_paths +``` + +## Flujo + +1. `assert_command_exists` — verifica que `sqlite3` esta disponible +2. `assert_file_exists` — verifica que `registry.db` existe y reporta su tamano +3. `validate_registry_paths` (functions) — itera todas las functions, verifica cada file_path +4. `validate_registry_paths` (types) — itera todos los types, verifica cada file_path +5. Genera `broken_paths.txt` con formato legible para agentes +6. `report_execution_json` — imprime JSON de ejecucion a stdout +7. `exit_with_status` — exit code segun resultado + +## Formato de salida + +``` +# Broken file_path entries in registry.db +# Generated: 2026-04-03T10:00:00Z +# Total: 11 broken paths +# +# Format: id | file_path (in .md) | domain | table +# --- + +## Functions (11) +cdp_click_go_browser | functions/infra/cdp_click.go | browser | functions +``` + +## Notas + +El archivo de salida es consumible por agentes: cada linea tiene el ID de la funcion/tipo y el file_path que necesita correccion. El agente puede leer el .md correspondiente, encontrar el archivo real en disco, y actualizar el campo `file_path`. diff --git a/bash/functions/pipelines/audit_registry_paths.sh b/bash/functions/pipelines/audit_registry_paths.sh new file mode 100644 index 00000000..7b8b3374 --- /dev/null +++ b/bash/functions/pipelines/audit_registry_paths.sh @@ -0,0 +1,134 @@ +#!/usr/bin/env bash +# audit_registry_paths +# -------------------- +# Audita file_path de functions y types en registry.db. +# Genera un txt con las rutas rotas para que agentes puedan arreglarlas. +# +# Compone: assert_command_exists + assert_file_exists + +# validate_registry_paths + report_execution_json + exit_with_status +# +# USO: +# ./audit_registry_paths.sh [OUTPUT_FILE] +# +# ARGUMENTOS (opcionales): +# OUTPUT_FILE Ruta del archivo de salida +# Default: $REGISTRY_ROOT/broken_paths.txt + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REGISTRY_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" + +source "$REGISTRY_ROOT/bash/functions/shell/assert_command_exists.sh" +source "$REGISTRY_ROOT/bash/functions/shell/assert_file_exists.sh" +source "$REGISTRY_ROOT/bash/functions/shell/validate_registry_paths.sh" +source "$REGISTRY_ROOT/bash/functions/shell/report_execution_json.sh" +source "$REGISTRY_ROOT/bash/functions/shell/exit_with_status.sh" + +OUTPUT_FILE="${1:-$REGISTRY_ROOT/broken_paths.txt}" +DB_PATH="$REGISTRY_ROOT/registry.db" + +STARTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ) +START_MS=$(date +%s%3N) +STEPS_FILE=$(mktemp) +trap 'rm -f "$STEPS_FILE"' EXIT + +ok_steps=0 +failed_steps=0 + +log_step() { + local name="$1" action="$2" status="$3" elapsed="$4" output="${5:-}" error="${6:-}" + printf '%s\t%s\t%s\t%s\t%s\t%s\n' "$name" "$action" "$status" "$elapsed" "$output" "$error" >> "$STEPS_FILE" + if [[ "$status" == "ok" ]]; then ok_steps=$((ok_steps + 1)); else failed_steps=$((failed_steps + 1)); fi +} + +# Paso 1: verificar sqlite3 +step_start=$(date +%s%3N) +if assert_command_exists sqlite3; then + log_step "assert_command_exists" "check sqlite3" "ok" $(( $(date +%s%3N) - step_start )) +else + log_step "assert_command_exists" "check sqlite3" "error" $(( $(date +%s%3N) - step_start )) "" "sqlite3 not found" + ENDED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ) + DURATION=$(( $(date +%s%3N) - START_MS )) + set +e; report_execution_json "audit_registry_paths" "failure" 1 "$STARTED_AT" "$ENDED_AT" "$DURATION" "$STEPS_FILE"; set -e + exit 1 +fi + +# Paso 2: verificar registry.db +step_start=$(date +%s%3N) +if db_size=$(assert_file_exists "$DB_PATH"); then + log_step "assert_file_exists" "check registry.db" "ok" $(( $(date +%s%3N) - step_start )) "${db_size} bytes" +else + log_step "assert_file_exists" "check registry.db" "error" $(( $(date +%s%3N) - step_start )) "" "registry.db not found" + ENDED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ) + DURATION=$(( $(date +%s%3N) - START_MS )) + set +e; report_execution_json "audit_registry_paths" "failure" 1 "$STARTED_AT" "$ENDED_AT" "$DURATION" "$STEPS_FILE"; set -e + exit 1 +fi + +# Paso 3: validar functions +step_start=$(date +%s%3N) +fn_broken=$(validate_registry_paths "$DB_PATH" functions "$REGISTRY_ROOT") +fn_count=$(printf '%s' "$fn_broken" | grep -c . || true) +log_step "validate_registry_paths" "check functions" "ok" $(( $(date +%s%3N) - step_start )) "$fn_count broken" + +# Paso 4: validar types +step_start=$(date +%s%3N) +ty_broken=$(validate_registry_paths "$DB_PATH" types "$REGISTRY_ROOT") +ty_count=$(printf '%s' "$ty_broken" | grep -c . || true) +log_step "validate_registry_paths" "check types" "ok" $(( $(date +%s%3N) - step_start )) "$ty_count broken" + +# Paso 5: generar archivo de salida +step_start=$(date +%s%3N) +total_broken=$(( fn_count + ty_count )) + +{ + echo "# Broken file_path entries in registry.db" + echo "# Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)" + echo "# Total: $total_broken broken paths" + echo "#" + echo "# Format: id | file_path (in .md) | domain | table" + echo "# ---" + if [[ $total_broken -eq 0 ]]; then + echo "# All paths are valid." + else + if [[ -n "$fn_broken" ]]; then + echo "" + echo "## Functions ($fn_count)" + printf '%s\n' "$fn_broken" | while IFS=$'\t' read -r id fp domain table; do + echo "$id | $fp | $domain | $table" + done + fi + if [[ -n "$ty_broken" ]]; then + echo "" + echo "## Types ($ty_count)" + printf '%s\n' "$ty_broken" | while IFS=$'\t' read -r id fp domain table; do + echo "$id | $fp | $domain | $table" + done + fi + fi +} > "$OUTPUT_FILE" + +log_step "write_output" "generate $OUTPUT_FILE" "ok" $(( $(date +%s%3N) - step_start )) "$total_broken entries" + +# Reporte final +ENDED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ) +DURATION=$(( $(date +%s%3N) - START_MS )) +total_steps=$(( ok_steps + failed_steps )) + +if [[ $total_broken -eq 0 ]]; then + status="success" +else + status="partial" +fi + +set +e +report_execution_json "audit_registry_paths" "$status" 0 "$STARTED_AT" "$ENDED_AT" "$DURATION" "$STEPS_FILE" +set -e + +echo "" +echo "--- Results ---" +echo "Broken paths: $total_broken" +echo "Output: $OUTPUT_FILE" + +exit_with_status "$total_steps" "$ok_steps" "$failed_steps" > /dev/null diff --git a/bash/functions/shell/validate_registry_paths.md b/bash/functions/shell/validate_registry_paths.md new file mode 100644 index 00000000..4f5b7063 --- /dev/null +++ b/bash/functions/shell/validate_registry_paths.md @@ -0,0 +1,37 @@ +--- +name: validate_registry_paths +kind: function +lang: bash +domain: shell +version: "1.0.0" +purity: impure +signature: "validate_registry_paths(db_path: string, table: string, root_dir: string) -> tsv_stdout" +description: "Consulta registry.db y verifica que cada file_path apunte a un archivo existente en disco. Imprime a stdout las rutas rotas en formato TSV (id, file_path, domain, tabla)." +tags: [registry, validation, paths, audit, bash] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/shell/validate_registry_paths.sh" +--- + +## Ejemplo + +```bash +source validate_registry_paths.sh +validate_registry_paths /home/lucas/fn_registry/registry.db functions /home/lucas/fn_registry + +# Output (TSV): +# cdp_click_go_browser functions/infra/cdp_click.go browser functions +``` + +## Notas + +Impura porque lee el filesystem y la base de datos. No modifica nada — solo reporta. + +La salida TSV es consumible por otros scripts o pipelines. Si no hay rutas rotas, no imprime nada. diff --git a/bash/functions/shell/validate_registry_paths.sh b/bash/functions/shell/validate_registry_paths.sh new file mode 100644 index 00000000..9a9120c7 --- /dev/null +++ b/bash/functions/shell/validate_registry_paths.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# validate_registry_paths +# ----------------------- +# Consulta registry.db y verifica que cada file_path apunte a un archivo existente. +# Recibe la ruta a registry.db y la tabla a validar (functions o types). +# Imprime a stdout las lineas con rutas rotas en formato TSV: +# idfile_pathdomaintabla +# Exit code 0 siempre (es una consulta, no una asercion). +# +# USO (sourced): +# source validate_registry_paths.sh +# validate_registry_paths /ruta/registry.db functions /ruta/raiz +# +# USO (directo): +# bash validate_registry_paths.sh /ruta/registry.db functions /ruta/raiz + +validate_registry_paths() { + local db_path="$1" + local table="$2" + local root_dir="$3" + + if [[ -z "$db_path" || -z "$table" || -z "$root_dir" ]]; then + echo "validate_registry_paths: uso: validate_registry_paths " >&2 + return 1 + fi + + if [[ "$table" != "functions" && "$table" != "types" ]]; then + echo "validate_registry_paths: tabla debe ser 'functions' o 'types'" >&2 + return 1 + fi + + local broken=0 + while IFS='|' read -r id fp domain; do + if [[ ! -f "$root_dir/$fp" ]]; then + printf '%s\t%s\t%s\t%s\n' "$id" "$fp" "$domain" "$table" + ((broken++)) + fi + done < <(sqlite3 "$db_path" "SELECT id, file_path, domain FROM $table ORDER BY id;") + + return 0 +} + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + validate_registry_paths "$@" +fi