services/api/src/scripts/lib/localMongoTarget.js

Overview

Este archivo define una guardia pura para los scripts administrativos de reconciliación D-09. Su propósito es validar un destino MongoDB antes de operar sobre él, y confirmar después de conectar que el servidor reportado sigue siendo local y no es un mongos. El propio archivo aclara que nunca conecta ni devuelve la URI; solo evalúa el destino y genera una huella estable sin credenciales.

Se usa como pieza compartida por los scripts de inventario y recuperación. Esos scripts llaman a assertLocalMongoTarget antes de conectar y a assertConnectedServerIsLocal después de hello, como parte de su verificación operativa del destino.

[!NOTE] El archivo documenta una limitación explícita: demostrar que la conexión es local y directa no demuestra que la base sea de pruebas. Un túnel local hacia otra base puede parecer indistinguible.

How it works

flowchart TD
    URI[Mongo URI] --> LOCAL[assertLocalMongoTarget]
    LOCAL --> SEED[evaluateSeedTarget]
    LOCAL --> QUERY[uriOptionNames]
    LOCAL --> DBCHK[allowedDb check]
    LOCAL --> RESULT1[allowed and reasons]

    HELLO[hello response] --> SERVER[assertConnectedServerIsLocal]
    SERVER --> HOST[hostOnly]
    SERVER --> MONGOS[reject mongos]
    SERVER --> LOCALMEM[loopback member check]
    SERVER --> RESULT2[allowed and reasons]

    URI --> FP[targetFingerprint]
    FP --> DESC[describeMongoTarget]
    FP --> CANON[canonical string]
    CANON --> HASH[sha256]

La ruta principal tiene tres pasos. Primero, assertLocalMongoTarget delega la evaluación base en evaluateSeedTarget desde seedTargetGuard.js, inspecciona opciones de URI, y compara la base detectada con allowedDb. Después, assertConnectedServerIsLocal revisa el documento hello y confirma que ningún miembro reportado salga de loopback, además de rechazar mongos. Por último, targetFingerprint calcula una huella reproducible a partir de esquema, hosts y base, sin incluir credenciales.

Key components

Estas funciones forman el núcleo del archivo y están pensadas para ser consumidas por otros scripts del backend. Las tres son exportadas y se usan como utilidades de validación o de derivación de huella.

{
    "title": "assertLocalMongoTarget",
    "content": "Eval\u00faa una URI de MongoDB contra la guardia local y devuelve allowed, reasons y database. Usa evaluateSeedTarget, bloquea opciones de URI inseguras y exige una base autorizada.",
    "type": "function",
    "filePath": "services/api/src/scripts/lib/localMongoTarget.js",
    "badges": [
        "public"
    ]
}
{
    "title": "assertConnectedServerIsLocal",
    "content": "Inspecciona la respuesta hello despu\u00e9s de conectar y rechaza miembros remotos o un mongos. Devuelve allowed y reasons.",
    "type": "function",
    "filePath": "services/api/src/scripts/lib/localMongoTarget.js",
    "badges": [
        "public"
    ]
}
{
    "title": "targetFingerprint",
    "content": "Calcula una huella SHA-256 estable del destino MongoDB usando esquema, hosts ordenados y base. No incluye credenciales.",
    "type": "function",
    "filePath": "services/api/src/scripts/lib/localMongoTarget.js",
    "badges": [
        "public"
    ]
}

Estas helpers no se exportan, pero explican parte del comportamiento del módulo.

  • uriOptionNames extrae los nombres de las opciones de query de la URI.
  • hostOnly normaliza una dirección para comparar solo el host.
  • ALLOWED_URI_OPTIONS define las únicas opciones de query aceptadas por esta guardia.
  • LOOPBACK define los hosts locales válidos para la comprobación post-conexión.

Data & fields

El archivo no define clases ni modelos de datos complejos. Su información principal son constantes read-only y la forma de los objetos que devuelven sus funciones.

Constantes internas

  • ALLOWED_URI_OPTIONS [badge:read-only] Set<string> — Solo acepta authsource y authmechanism.
  • LOOPBACK [badge:read-only] Set<string> — Solo acepta localhost, 127.0.0.1 y ::1.

Resultado de assertLocalMongoTarget

[
    {
        "name": "allowed",
        "type": "boolean",
        "required": true,
        "description": "Indica si la URI cumple todas las reglas aplicadas por la guardia."
    },
    {
        "name": "reasons",
        "type": "string[]",
        "required": true,
        "description": "Lista de motivos de rechazo. Cada motivo usa un código corto."
    },
    {
        "name": "database",
        "type": "string",
        "required": true,
        "description": "Base de datos detectada en la URI o cadena vacía si no pudo determinarse."
    }
]

Parámetros de assertLocalMongoTarget

[
    {
        "name": "uri",
        "type": "string",
        "required": true,
        "description": "URI de MongoDB que se quiere validar."
    },
    {
        "name": "options",
        "type": "object",
        "description": "Opciones adicionales para la validación del destino.",
        "children": [
            {
                "name": "allowedDb",
                "type": "string",
                "description": "Nombre de base autorizado. Debe coincidir con la base detectada."
            },
            {
                "name": "env",
                "type": "object",
                "description": "Entorno que se pasa a evaluateSeedTarget.",
                "children": [
                    {
                        "name": "NODE_ENV",
                        "type": "string",
                        "description": "Se reenvía a evaluateSeedTarget como nodeEnv."
                    },
                    {
                        "name": "APP_ENV",
                        "type": "string",
                        "description": "Se reenvía a evaluateSeedTarget como appEnv."
                    }
                ]
            }
        ]
    }
]

Resultado de assertConnectedServerIsLocal

  • allowed [badge:required] boolean — true solo cuando no hay razones de rechazo.
  • reasons [badge:required] string[] — Motivos de rechazo, como MONGOS_NOT_ALLOWED o REMOTE_MEMBER_REPORTED.

Parámetros de assertConnectedServerIsLocal

[
    {
        "name": "hello",
        "type": "object",
        "description": "Documento hello devuelto por MongoDB.",
        "children": [
            {
                "name": "msg",
                "type": "string",
                "description": "Si vale isdbgrid, el destino se rechaza."
            },
            {
                "name": "me",
                "type": "string",
                "description": "Dirección del miembro local que reporta el servidor."
            },
            {
                "name": "primary",
                "type": "string",
                "description": "Dirección del primario que reporta el servidor."
            },
            {
                "name": "hosts",
                "type": "string[]",
                "description": "Miembros del replica set que reporta el servidor."
            },
            {
                "name": "passives",
                "type": "string[]",
                "description": "Miembros pasivos que reporta el servidor."
            },
            {
                "name": "arbiters",
                "type": "string[]",
                "description": "Miembros árbitro que reporta el servidor."
            }
        ]
    }
]

Behaviors

Las funciones exportadas cubren tres responsabilidades distintas: validación previa, verificación post-conexión y derivación de identidad estable del destino. Los motivos de rechazo se expresan como códigos cortos, y assertLocalMongoTarget los normaliza quitando cualquier sufijo posterior a : que venga de evaluateSeedTarget.

  • assertLocalMongoTarget [badge:public] — Valida la URI y devuelve si el destino está permitido, junto con los motivos y la base detectada.
  • assertConnectedServerIsLocal [badge:public] — Comprueba el hello devuelto por MongoDB y rechaza miembros remotos o mongos.
  • targetFingerprint [badge:public] — Genera una huella SHA-256 del destino sin credenciales.
  • uriOptionNames — Extrae los nombres de las opciones de query de la URI, los normaliza a minúsculas y descarta vacíos.
  • hostOnly — Normaliza direcciones IPv4, IPv6 entre corchetes y valores con puerto.

assertLocalMongoTarget

La función toma una URI y un objeto de opciones. Luego llama a evaluateSeedTarget con uri, NODE_ENV y APP_ENV. Después, revisa las opciones de query y solo admite authSource y authMechanism; cualquier otra opción suma UNSAFE_URI_OPTION. También exige allowedDb; si falta, devuelve ALLOWED_DB_MISSING. Si la base detectada no coincide con allowedDb, devuelve DATABASE_NOT_AUTHORIZED.

assertConnectedServerIsLocal

La función inspecciona la respuesta hello. Si hello.msg === "isdbgrid", agrega MONGOS_NOT_ALLOWED. Luego reúne hello.me, hello.primary, hello.hosts, hello.passives y hello.arbiters, y verifica que cada dirección sea loopback después de normalizarla con hostOnly. Si encuentra alguna dirección remota, agrega REMOTE_MEMBER_REPORTED.

targetFingerprint

La función llama a describeMongoTarget(uri) desde seedTargetGuard.js. Si el destino no puede describirse, devuelve null. Si sí puede, construye una cadena canónica con scheme, los hosts ordenados y la base, y la firma con sha256. El resultado es una huella estable que no expone usuario, contraseña ni parámetros de query.

hostOnly trata dos formatos de forma explícita:

  • Direcciones IPv6 entre corchetes, como [::1]:27017.
  • Direcciones con puerto único, como localhost:27017.

La función deja el host listo para compararlo con LOOPBACK. Esto permite validar de forma uniforme la respuesta hello de MongoDB.

Gotchas & edge cases

[!WARNING] Esta guardia no demuestra que la base sea de pruebas. El propio archivo advierte que una conexión local puede apuntar a otra base mediante un túnel local indistinguible.

[!WARNING] assertLocalMongoTarget solo acepta authSource y authMechanism en la query de la URI. Cualquier otra opción suma un rechazo UNSAFE_URI_OPTION.

[!CAUTION] assertConnectedServerIsLocal solo analiza el documento hello. No valida contenido de la base ni estado de los datos, solo el origen y la topología reportada.

[!NOTE] targetFingerprint no incluye credenciales. Dos URIs diferentes pueden producir la misma huella si comparten esquema, hosts y base.

[!IMPORTANT] Este módulo forma parte del flujo operativo de los scripts de inventario y recuperación. Esos scripts lo usan antes y después de conectar, y además fijan directConnection en su propia conexión.

Este archivo está ligado a services/api/src/scripts/lib/seedTargetGuard.js, porque reutiliza evaluateSeedTarget y describeMongoTarget para interpretar y describir la URI de destino.

También se conecta con services/api/src/scripts/inventoryDeletionState.js y services/api/src/scripts/resumePendingRequirementDeletions.js, que lo importan para validar el destino antes de operar sobre MongoDB. Esos scripts primero rechazan destinos no autorizados y luego repiten la comprobación con hello tras conectar.

En el contexto del repositorio, el módulo aparece como parte de las utilidades de reconciliación y mantenimiento documentadas en los scripts de inventario y recuperación, no como una API HTTP ni como una capa de negocio general.