Files
dh-inspeccion-v2/scripts/phase-d5-3-acceptance.sh
T

167 lines
7.6 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -Eeuo pipefail
dhv2_base_url="${DHV2_BASE_URL:-https://dhv2.korexlabs.com}"
dhv2_base_url="${dhv2_base_url%/}"
fail() {
echo "ERROR: $*" >&2
exit 1
}
echo "========== D5.3 · MIGRACIONES =========="
dhv2_migration_status="$(docker compose --profile tools run --rm migrate npm run migration:show 2>&1)"
grep -q 'Pending migrations: no' <<<"$dhv2_migration_status" || fail "Quedaron migraciones pendientes"
echo "Migraciones pendientes: no"
echo
echo "========== D5.3 · HEALTH =========="
dhv2_internal="$(curl -fsS --connect-timeout 10 --max-time 30 http://127.0.0.1:3101/api/v3/health)"
dhv2_external="$(curl -fsS --connect-timeout 10 --max-time 30 "$dhv2_base_url/api/v3/health")"
grep -q '"version":"0.19.3"' <<<"$dhv2_internal" || fail "Health interno no informa v0.19.3"
grep -q '"phase":"D5.3"' <<<"$dhv2_internal" || fail "Health interno no informa D5.3"
grep -q '"version":"0.19.3"' <<<"$dhv2_external" || fail "Health externo no informa v0.19.3"
grep -q '"database":"ok"' <<<"$dhv2_external" || fail "La base no está saludable"
echo "$dhv2_external"
echo
echo "========== D5.3 · RUTA OPERATIVA PROTEGIDA =========="
dhv2_code="$(curl -sS --connect-timeout 10 --max-time 30 \
-o /tmp/dhv2-d5-3-response.json -w '%{http_code}' \
"$dhv2_base_url/api/v3/asset-operational-relations/areas")"
test "$dhv2_code" = "401" || fail "/api/v3/asset-operational-relations/areas devolvió HTTP $dhv2_code; se esperaba 401"
rm -f /tmp/dhv2-d5-3-response.json
echo "/api/v3/asset-operational-relations/areas sin sesión: 401 OK"
echo
echo "========== D5.3 · MODELO OPERATIVO =========="
dhv2_db_check="$(docker compose exec -T db sh -lc \
'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=1 -v app_user="$APP_DB_USER" -At' <<'SQL'
SELECT 'operational_role_enum', COUNT(*)
FROM pg_enum enum_value
INNER JOIN pg_type enum_type ON enum_type.oid = enum_value.enumtypid
WHERE enum_type.typname = 'asset_type_operational_role';
SELECT 'asset_type_role_column', COUNT(*)
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'asset_types'
AND column_name = 'operational_role';
SELECT 'asset_operational_columns', COUNT(*)
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'assets'
AND column_name IN ('operational_area_id', 'operator_company_id');
SELECT 'relations_table', COUNT(*)
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'area_company_relations';
SELECT 'relations_constraints', COUNT(*)
FROM information_schema.table_constraints
WHERE table_schema = 'public'
AND table_name = 'area_company_relations'
AND constraint_name IN (
'chk_area_company_relation_dates',
'chk_area_company_relation_start_reason',
'chk_area_company_relation_end_reason',
'fk_area_company_relation_area',
'fk_area_company_relation_company',
'fk_area_company_relation_created_by',
'fk_area_company_relation_ended_by'
);
SELECT 'active_pair_unique_index', COUNT(*)
FROM pg_indexes
WHERE schemaname = 'public'
AND tablename = 'area_company_relations'
AND indexname = 'uq_area_company_relations_active_pair';
SELECT 'operational_triggers', COUNT(DISTINCT trigger_name)
FROM information_schema.triggers
WHERE event_object_schema = 'public'
AND trigger_name IN (
'trg_asset_types_protect_operational_changes',
'trg_area_company_relation_roles',
'trg_assets_operational_context',
'trg_assets_operational_descendants',
'trg_assets_protect_operational_anchor_inactivation'
);
SELECT 'relation_read_roles', COUNT(*)
FROM role_permissions role_permission
INNER JOIN roles role ON role.id = role_permission.role_id
INNER JOIN permissions permission ON permission.id = role_permission.permission_id
WHERE role.code IN ('admin', 'director', 'supervisor', 'inspector', 'auditor')
AND permission.code = 'asset_relations.read';
SELECT 'relation_manage_roles', COUNT(*)
FROM role_permissions role_permission
INNER JOIN roles role ON role.id = role_permission.role_id
INNER JOIN permissions permission ON permission.id = role_permission.permission_id
WHERE role.code IN ('admin', 'supervisor')
AND permission.code = 'asset_relations.manage';
SELECT 'relation_select', has_table_privilege(:'app_user', 'area_company_relations', 'SELECT');
SELECT 'relation_insert', has_table_privilege(:'app_user', 'area_company_relations', 'INSERT');
SELECT 'relation_update', has_table_privilege(:'app_user', 'area_company_relations', 'UPDATE');
SELECT 'relation_delete', has_table_privilege(:'app_user', 'area_company_relations', 'DELETE');
SELECT 'asset_versions_backfilled', NOT EXISTS (
SELECT 1
FROM asset_versions
WHERE NOT (snapshot->'type' ? 'operationalRole')
OR NOT (snapshot ? 'operationalArea')
OR NOT (snapshot ? 'operatorCompany')
);
SELECT 'operational_pair_integrity', NOT EXISTS (
SELECT 1 FROM assets
WHERE (operational_area_id IS NULL) <> (operator_company_id IS NULL)
);
SELECT 'migration_applied', COUNT(*)
FROM typeorm_migrations
WHERE name = 'PhaseD53OperationalContext1787421600000';
SQL
)"
grep -q 'operational_role_enum|3' <<<"$dhv2_db_check" || fail "El enum operativo no tiene los tres roles esperados"
grep -q 'asset_type_role_column|1' <<<"$dhv2_db_check" || fail "Falta operational_role en asset_types"
grep -q 'asset_operational_columns|2' <<<"$dhv2_db_check" || fail "Faltan columnas de contexto operativo en assets"
grep -q 'relations_table|1' <<<"$dhv2_db_check" || fail "No se creó area_company_relations"
grep -q 'relations_constraints|7' <<<"$dhv2_db_check" || fail "Faltan restricciones de integridad en relaciones ÁreaEmpresa"
grep -q 'active_pair_unique_index|1' <<<"$dhv2_db_check" || fail "Falta unicidad del vínculo activo ÁreaEmpresa"
grep -q 'operational_triggers|5' <<<"$dhv2_db_check" || fail "Faltan triggers de integridad operativa"
grep -q 'relation_read_roles|5' <<<"$dhv2_db_check" || fail "Los roles de consulta no recibieron asset_relations.read"
grep -q 'relation_manage_roles|2' <<<"$dhv2_db_check" || fail "Admin y supervisor no recibieron asset_relations.manage"
grep -q 'relation_select|t' <<<"$dhv2_db_check" || fail "La API no puede leer relaciones operativas"
grep -q 'relation_insert|t' <<<"$dhv2_db_check" || fail "La API no puede crear relaciones operativas"
grep -q 'relation_update|t' <<<"$dhv2_db_check" || fail "La API no puede finalizar relaciones operativas"
grep -q 'relation_delete|f' <<<"$dhv2_db_check" || fail "La API no debe borrar relaciones operativas"
grep -q 'asset_versions_backfilled|t' <<<"$dhv2_db_check" || fail "Hay snapshots históricos sin los campos de D5.3"
grep -q 'operational_pair_integrity|t' <<<"$dhv2_db_check" || fail "Hay activos con contexto operativo incompleto"
grep -q 'migration_applied|1' <<<"$dhv2_db_check" || fail "La migración D5.3 no figura aplicada"
echo "$dhv2_db_check"
echo
echo "========== D5.3 · API COMPILADA =========="
docker compose exec -T api sh -lc \
'grep -R "AssetOperationalRelationsController" /app/dist >/dev/null && grep -R "ASSET_AREA_COMPANY_RELATION_CREATED" /app/dist >/dev/null && grep -R "ASSET_HIERARCHY_MOVE_BREAKS_OPERATIONAL_CONTEXT" /app/dist >/dev/null'
echo "Relaciones, auditoría y validaciones operativas cargadas: OK"
echo
echo "========== D5.3 · DASHBOARD =========="
docker compose exec -T web sh -lc \
'grep -R "0.19.3" /usr/share/nginx/html/assets >/dev/null && grep -R "Contexto operativo" /usr/share/nginx/html/assets >/dev/null && grep -R "Relaciones operativas" /usr/share/nginx/html/assets >/dev/null && grep -R "Empresa explotadora" /usr/share/nginx/html/assets >/dev/null'
echo "Contexto ÁreaEmpresa y footer v0.19.3: OK"
echo
echo "========== D5.3 · CONTENEDORES =========="
docker compose ps
echo
echo "ACEPTACIÓN DE FASE D5.3: OK"