diff --git a/.github/workflows/osv-scanner.yml b/.github/workflows/osv-scanner.yml index f0f689a..d97c44f 100644 --- a/.github/workflows/osv-scanner.yml +++ b/.github/workflows/osv-scanner.yml @@ -3,20 +3,21 @@ # separate terms of service, privacy policy, and support # documentation. -# Full-lockfile OSV scan: every pull request, push to main, and weekly. +# Full-lockfile OSV scan: every pull request/push to main or develop, plus daily +# on the default branch so newly published advisories do not wait a week. # Findings remain visible as SARIF/CVSS; do not suppress vulnerabilities. name: OSV-Scanner on: pull_request: - branches: [ "main" ] + branches: [ "main", "develop" ] merge_group: - branches: [ "main" ] + branches: [ "main", "develop" ] schedule: - - cron: '33 13 * * 1' + - cron: '33 13 * * *' push: - branches: [ "main" ] + branches: [ "main", "develop" ] permissions: # Require writing security events to upload SARIF file to security tab diff --git a/Cargo.lock b/Cargo.lock index cfaecfc..3907592 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -877,9 +877,9 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" +checksum = "6bb08299a6046833a879ace115697f12fd2bd6c8d3e93c909ffc9e0738e7cae0" dependencies = [ "cpubits", "ctutils", @@ -933,9 +933,9 @@ dependencies = [ [[package]] name = "ctutils" -version = "0.4.2" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +checksum = "fe3e9d21d39e6f39ff46e03d5b621424f88ee23d8a1672c6bfc9ccc7f2da4f6a" dependencies = [ "cmov", "subtle", @@ -2958,9 +2958,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quinn" -version = "0.11.11" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11" dependencies = [ "bytes", "cfg_aliases", @@ -2978,9 +2978,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.16" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe" dependencies = [ "bytes", "fastbloom", @@ -3433,9 +3433,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.45" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "aws-lc-rs", "log", @@ -3498,9 +3498,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.15" +version = "0.103.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281" dependencies = [ "aws-lc-rs", "ring", @@ -4119,7 +4119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.3", + "getrandom 0.3.4", "once_cell", "rustix", "windows-sys 0.61.2", @@ -4224,9 +4224,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.53.1" +version = "1.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +checksum = "ce3335fa71841cda333a58d7615b03901380ecf09d59b3296d21f8bbac0dde4e" dependencies = [ "bytes", "libc", @@ -4636,18 +4636,18 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" +checksum = "58ec80e73fd8baf57bf0d9615554c75348bda990d6d5bbeab964dd068319fecb" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +checksum = "1c1c8e20c8a38fc7d65abfe74eb7280e4aa667e8eec8bc84996d2874810748d9" dependencies = [ "rustls-pki-types", ] @@ -4680,7 +4680,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8cf80f9..190cb5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,7 +94,7 @@ mdns-sd = "0.20" sysinfo = "0.39" # QUIC transport -quinn = "0.11" +quinn = "0.11.12" rustls = "0.23" # PEM loading is built into rustls 0.23 via pki_types::PemObject rcgen = "0.14" diff --git a/docs/security/PLAN-2026-10-27-dependabot-release.md b/docs/security/PLAN-2026-10-27-dependabot-release.md new file mode 100644 index 0000000..9a7374b --- /dev/null +++ b/docs/security/PLAN-2026-10-27-dependabot-release.md @@ -0,0 +1,115 @@ +# Plan de remediación de seguridad y release de Synapsis + +**Estado:** remediación local validada; integración y publicación pendientes +**Repositorio:** `MethodWhite/synapsis` +**Rama de trabajo:** `codex/synapsis-security-release-20261027` +**Línea base revisada:** `main` en `25bab13` (v0.13.1) +**Fecha:** 2026-10-27 + +## 1. Objetivo y alcance + +Remediar las alertas abiertas de Dependabot del SDK `packages/synapsis-client`, integrar la corrección vigente de Quinn/RustSec que ya está propuesta para `main`, mantener el escaneo OSV en las ramas de publicación y desarrollo, validar el resultado sin relajar el acceso a dependencias privadas y producir un release cuyo commit/tag contenga las correcciones. + +La revisión encontró seis alertas Dependabot abiertas, todas para Vite `8.3.2` en el lockfile del SDK y marcadas como dependencias de desarrollo. El PR #83 propone Vite `8.3.5`. Las seis advisories consideran afectada la línea `8.3.0–8.3.2` y fijada desde `8.3.3`; `8.3.5` supera esa versión. El riesgo es de herramientas de desarrollo/build, no evidencia de una vulnerabilidad explotable en el SDK publicado. La exposición concreta depende de las condiciones descritas por cada advisory. + +La auditoría actual de `Cargo.lock` añadió hallazgos RustSec posteriores a los PR revisados: Tokio, rustls, rustls-webpki, raíces WebPKI y componentes criptográficos. Se fijaron versiones corregidas para esas vulnerabilidades; `crypto-bigint 0.7.6` queda como advertencia yanked de Cargo porque es la versión upstream que RustSec señala como corregida. + +El escaneo OSV completo reportó GHSA-qwgh-2vcv-g2f7 contra `block-buffer 0.10.4`. La revisión directa de la etiqueta upstream `block-buffer-v0.10.4` y la confirmación del mantenedor de RustCrypto establecen que esa versión no está afectada por este defecto: su cursor se almacena por separado del buffer. El advisory upstream ya informa el rango `>=0.11.0, <0.12.1`; la ficha central de GitHub Advisory Database y OSV aún conservan el rango anterior, por lo que el CI de Synapsis sigue fallando. Hay una corrección propuesta en [github/advisory-database#10698](https://github.com/github/advisory-database/pull/10698); se dejó allí evidencia independiente y una observación para reconciliar el límite prerelease con el rango upstream. No se añadió ningún ignore ni se afirma que Synapsis tenga esta vulnerabilidad. El gate de publicación queda a la espera de que la ficha central se corrija y que el escaneo completo vuelva a pasar. + +El paquete no tenía archivos de prueba aunque declaraba `vitest run`; se añadieron tres pruebas unitarias acotadas al contrato existente de `SynapsisClient.callTool` (JSON-RPC, cabecera de autenticación y errores) para que `npm test` tenga una señal real durante esta actualización. + +También hay un PR de seguridad Quinn para `main` (#79), con `quinn 0.11.12` y `quinn-proto 0.11.19`, aprobado y con CI verde al iniciar esta revisión. El PR #82 lleva remediaciones equivalentes a `develop`, pero aún no tiene una aprobación registrada en GitHub. El PR release-please #78 prepara v0.14.0; debe incluir las correcciones antes de publicar. + +## 2. Inventario de hallazgos Dependabot + +| Alerta | Severidad | Advisory | Riesgo resumido | Versión fijada | +|---|---|---|---|---| +| #16 | Media | GHSA-rq7h-c2jc-7f22 | Posible lectura de archivos fuera de `server.fs.allow` con rutas que coinciden con paths del sistema | Vite 8.3.3+ | +| #15 | Baja | GHSA-9jrq-w75r-8gcw | Ejecución de script cross-origin bajo ciertas configuraciones de middleware | Vite 8.3.3+ | +| #14 | Media | GHSA-vfpm-58rq-9qcg | Exposición de los primeros bytes de archivos fuera de `server.fs` mediante `vite-wasm-instance` | Vite 8.3.3+ | +| #13 | Alta | GHSA-587h-7wmj-h5pm | Bypass de comprobación de ruta de `launch-editor` en Windows | Vite 8.3.3+ | +| #12 | Media | GHSA-r825-w8mm-5pxw | Interpretación de argumentos por algunos editores que puede conducir a ejecución de comandos | Vite 8.3.3+ | +| #11 | Media | GHSA-698v-4r3x-3vcv | Escape incompleto de `%` en Windows en ciertos escenarios de `launch-editor` | Vite 8.3.3+ | + +Las seis alertas apuntan al manifiesto `packages/synapsis-client/package-lock.json`; ninguna está marcada como dependencia de runtime. El nivel alto está condicionado a Windows y a que un atacante controle el argumento/ruta descrito por el advisory. + +## 3. RCTF + +En este plan, **RCTF** significa **Riesgo, Controles, Trazabilidad y Fallback**. + +### R — Riesgo + +- Mantener Vite `8.3.2` conserva seis advisories conocidas en la herramienta de desarrollo. +- Mantener versiones anteriores de Tokio, rustls, rustls-webpki, las raíces WebPKI y crypto-bigint conserva advisories RustSec, incluidos riesgos de seguridad de I/O, certificados TLS y operaciones criptográficas de tiempo constante. +- `crypto-bigint 0.7.6` está yanked pese a ser la versión corregida indicada por RustSec; actualizarla limpia vulnerabilidades pero conserva una advertencia que requiere decisión de mantenimiento. +- La ficha central OSV aún identifica `block-buffer 0.10.4` (GHSA-qwgh-2vcv-g2f7) como afectado, pero la fuente exacta y el mantenedor upstream confirman que 0.10.4 no está afectado por este defecto. La línea 0.11 introdujo el cursor inline que causa el problema; la versión 0.12.1 lo corrige. +- Mientras la base central de GHSA/OSV no sincronice el rango corregido, el escaneo fail-closed de Synapsis dará un falso positivo. No debe resolverse ocultando o excluyendo el advisory del escaneo. +- Publicar desde una rama de release creada antes de integrar estas correcciones dejaría el tag sin ellas, aunque los PR de seguridad sigan abiertos o pasen pruebas individualmente. +- Los PR de Dependabot no reciben secretos privados de Actions; el PR #83 ya falló al clonar Arca y el escaneo completo encontró avisos Quinn presentes en su base. Estos fallos no se tratarán como PASS ni se resolverán ampliando permisos. + +### C — Controles + +- Fijar el árbol reproducible en `package-lock.json` a Vite `8.3.5`; confirmar el paquete resuelto y el árbol npm, no solo el rango de `package.json`. +- Integrar la actualización Quinn y la exploración OSV sin agregar excepciones o ignores para los advisories. +- Mantener el token de repositorios privados limitado a los jobs que lo requieren. No publicar Arca, no mover secretos al PR ni usar `pull_request_target` para habilitar secretos a Dependabot. +- Ejecutar revisión independiente Oura y verificar cada hallazgo contra el lockfile, advisories oficiales, salida de npm/Cargo y checks de CI. La auditoría local de Cargo terminó con cero vulnerabilidades RustSec y una advertencia yanked; OSV encontró GHSA-qwgh-2vcv-g2f7 por rango central desactualizado y falló como gate. +- El release debe apuntar a un SHA que ya contenga todas las correcciones aceptadas, changelog/manifest calculados desde ese estado y escaneo final limpio. + +### T — Trazabilidad y pruebas + +- Registrar alerta/advisory, manifiesto, rango afectado, versión corregida y evidencia de cierre. +- Validar el SDK: `npm ci`, `npm audit --audit-level=low`, `npm run build` y `npm test`. +- Validar Rust: `cargo audit`, `cargo deny check` (CI; cargo-deny no está instalado en este entorno), `cargo test --locked --features arca -- --test-threads=1`, `cargo check --locked --features arca` y `cargo fmt --check`. +- Validar el repositorio completo con OSV Scanner y los jobs de Linux, macOS, Windows, MSRV, seguridad, convenciones y workflows aplicables. +- Después de integrar, consultar de nuevo las alertas Dependabot y el release/tag de GitHub; un PR verde por sí solo no cierra el objetivo. + +### F — Fallback y recuperación + +- Si npm/Cargo cambia resolución fuera de lo esperado, restaurar únicamente el lockfile desde la rama de trabajo y rehacer la actualización de manera reproducible; no editar a mano hashes o integridades. +- Si una prueba falla por Arca inaccesible, conservar el error como bloqueo, corregir el acceso en la configuración de CI con el alcance mínimo o reejecutar en el contexto autorizado. No marcar la prueba como aprobada ni debilitar el control. +- Si aparecen nuevas advisories o incompatibilidades, detener el release, actualizar el inventario y escoger la versión mínima fijada compatible; no publicar un tag parcial. +- Si CI o el mantenedor rechaza la versión yanked `crypto-bigint 0.7.6`, detener el release y actualizar Arca/K-256 o su árbol criptográfico a una versión upstream aceptable; no ocultar el aviso en Cargo audit. +- Si el release-please #78 no contiene el SHA y las notas de seguridad, actualizar/regenerar el PR de release antes de publicarlo; conservar tags existentes y no reescribir historia. + +## 4. Fases y gates + +1. **Baseline:** confirmar repo, ramas, alerts, PRs, versiones y estado de CI; registrar SHAs y no tocar los checkouts con cambios preexistentes. +2. **Remediación:** incorporar el bump de Vite a `8.3.5`, la corrección Quinn de `main` y el escaneo OSV diario para `main`/`develop`; revisar que el lockfile no introduzca paquetes inesperados. +3. **Validación local e independiente:** ejecutar las validaciones de npm/Cargo indicadas, revisar el diff y solicitar Oura; confirmar cada salida de forma independiente. Cualquier advertencia yanked debe quedar explícita y ser aceptada por la revisión/CI antes de publicar. +4. **Integración:** publicar un PR de mantenimiento normal con el token privado disponible para el CI autorizado. Resolver o cerrar PRs duplicados solo después de comprobar que su cambio está incluido y sus alertas se resuelven. +5. **Rama de desarrollo:** revisar por separado el PR #82 a `develop`; incorporarlo solo con revisión de diff y CI válido, conservando la separación de ramas. +6. **Release:** actualizar el PR release-please #78 o el PR que lo sustituya para que el tag planificado contenga las correcciones. Ejecutar el gate final sobre el SHA exacto del release; publicar solo con todos los gates obligatorios verdes. + +## 5. Resultados esperados + +- Las seis alertas Dependabot se cierran automáticamente tras integrar el lockfile fijado a Vite `8.3.5`. +- Quinn/`quinn-proto` queda en versiones fijadas sin los advisories cubiertos; OSV vuelve a escanear diariamente y en PR/push/merge queue de `main` y `develop`. +- `npm audit` y `cargo audit` no reportan vulnerabilidades abiertas para los manifests/lockfiles del release; no se añaden ignores. El resultado local actual de Cargo es cero vulnerabilidades y una advertencia (`crypto-bigint 0.7.6` yanked); OSV completo aún falla hasta que la base central corrija el rango de GHSA-qwgh-2vcv-g2f7. +- Build, pruebas y checks requeridos pasan; el resultado de Windows se informa explícitamente, considerando que el job actual está configurado como `continue-on-error`. +- Las tres pruebas del SDK verifican la serialización del request MCP, el envío de bearer token y el manejo de errores JSON-RPC. +- El changelog, manifest, versión, tag y artefactos del release corresponden al SHA que contiene las correcciones. La versión exacta la determina release-please después de reconciliar el PR #78; no se fija manualmente en este plan. +- No hay cambios funcionales intencionales al API/runtime del SDK ni al comportamiento del servicio: la actualización Vite es de desarrollo y Quinn es una actualización de dependencias con compatibilidad comprobada por la suite. + +## 6. Resultados que no se admiten + +- Cerrar/silenciar alertas, añadir excepciones a Cargo audit/OSV o afirmar remediación basándose solo en un PR abierto. +- Publicar un tag/release cuyo SHA no incluya los locks corregidos y las notas pertinentes. +- Publicar mientras cargo-deny/CI no haya validado el lockfile, OSV siga fallando por el rango central desactualizado de GHSA-qwgh-2vcv-g2f7, o sin decisión documentada sobre `crypto-bigint 0.7.6` yanked. +- Interpretar los fallos del PR #83 por falta de secreto privado como pruebas aprobadas, o conceder secretos privados a un PR de Dependabot. +- Afirmar impacto en producción a partir de una dependencia marcada solo de desarrollo, o afirmar seguridad absoluta a partir de Oura/audit aislados. +- Perder, sobrescribir o reescribir trabajo local existente; forzar push, borrar tags, publicar Arca o modificar permisos/credenciales. +- Marcar como terminada la línea `develop` si #82 queda sin revisión o sin evidencia de integración. + +## 7. Criterio de cierre + +La tarea se cierra cuando el release publicado se identifica por versión, tag y SHA verificables; contiene las correcciones de Vite, Quinn y RustSec, los seis avisos Dependabot están cerrados, OSV/npm/Cargo no presentan vulnerabilidades abiertas relacionadas, cargo-deny y los gates obligatorios están verdes, se ha resuelto o aceptado formalmente la advertencia yanked de `crypto-bigint`, GHSA-qwgh-2vcv-g2f7 tiene su rango central corregido y el escaneo completo pasa sin excepciones, y la remediación de `develop` quedó integrada o registrada con evidencia y responsable como única excepción pendiente. + +## 8. Estado de ejecución y evidencia local + +- Rama `codex/synapsis-security-release-20261027`, basada en `origin/main` `25bab13`; tres commits cherry-picked de remediaciones previas (Quinn, Vite y OSV) y lockfile Cargo actualizado localmente. +- `packages/synapsis-client`: `npm ci`, `npm run build`, `npm test` (3 pruebas) y `npm audit --audit-level=low` pasaron; Vite resuelve a `8.3.5`, auditoría npm informa 0 vulnerabilidades. +- Rust: `cargo check --locked --features arca`, `cargo test --locked --features arca -- --test-threads=1` (suite completa; 1 ignorada), `cargo fmt --check` y `cargo audit` pasaron. Cargo audit informó 0 vulnerabilidades y una advertencia yanked para `crypto-bigint 0.7.6`. +- `cargo deny check` no se pudo ejecutar localmente: el subcomando `cargo-deny` no está instalado. En PR #84, el job remoto Cargo Deny pasó. +- Oura informó sin vulnerabilidades en el conjunto revisado y sin violaciones de código limpio; esto complementa, pero no reemplaza, Cargo audit/deny ni CI. +- CI de PR #84 confirmó el acceso a los repos privados en jobs de mantenedor; Cargo Deny, auditoría de seguridad, pruebas Linux/macOS/Windows, MSRV, formato, clippy, SBOM y Geiger pasaron. El escaneo OSV rápido pasa, pero el scan completo falla por el rango central desactualizado de `GHSA-qwgh-2vcv-g2f7` contra `block-buffer 0.10.4`. Oura no encontró vulnerabilidades al analizar el lockfile y la fuente 0.10.4; la revisión directa concuerda con el mantenedor upstream. +- El repositorio upstream RustCrypto confirma que 0.10.x no está afectado y su API ya muestra `>=0.11.0, <0.12.1`. El PR de corrección central #10698 sigue abierto. Se comentó allí la verificación y la diferencia entre `0.11.0-pre` propuesta y `0.11.0` publicado upstream. PR #84 sigue abierto y no hay release publicado. Pendiente: sincronización central, rerun OSV completo, revisión humana, merge y reconciliación/publicación release-please. diff --git a/packages/synapsis-client/package-lock.json b/packages/synapsis-client/package-lock.json index 4e45efb..e1034eb 100644 --- a/packages/synapsis-client/package-lock.json +++ b/packages/synapsis-client/package-lock.json @@ -42,9 +42,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.152.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.152.0.tgz", - "integrity": "sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==", + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz", + "integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==", "dev": true, "license": "MIT", "peer": true, @@ -53,9 +53,9 @@ } }, "node_modules/@rolldown/binding-android-arm-eabi": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.12.tgz", - "integrity": "sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.15.tgz", + "integrity": "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==", "cpu": [ "arm" ], @@ -71,9 +71,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.12.tgz", - "integrity": "sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.15.tgz", + "integrity": "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==", "cpu": [ "arm64" ], @@ -89,9 +89,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.12.tgz", - "integrity": "sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.15.tgz", + "integrity": "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==", "cpu": [ "arm64" ], @@ -107,9 +107,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.12.tgz", - "integrity": "sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.15.tgz", + "integrity": "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==", "cpu": [ "x64" ], @@ -125,9 +125,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.12.tgz", - "integrity": "sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.15.tgz", + "integrity": "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==", "cpu": [ "x64" ], @@ -143,9 +143,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.12.tgz", - "integrity": "sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.15.tgz", + "integrity": "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==", "cpu": [ "arm" ], @@ -161,9 +161,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.12.tgz", - "integrity": "sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.15.tgz", + "integrity": "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==", "cpu": [ "arm64" ], @@ -182,9 +182,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.12.tgz", - "integrity": "sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.15.tgz", + "integrity": "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==", "cpu": [ "arm64" ], @@ -203,9 +203,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.12.tgz", - "integrity": "sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.15.tgz", + "integrity": "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==", "cpu": [ "ppc64" ], @@ -224,9 +224,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.12.tgz", - "integrity": "sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.15.tgz", + "integrity": "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==", "cpu": [ "s390x" ], @@ -245,9 +245,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.12.tgz", - "integrity": "sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.15.tgz", + "integrity": "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==", "cpu": [ "x64" ], @@ -266,9 +266,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.12.tgz", - "integrity": "sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.15.tgz", + "integrity": "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==", "cpu": [ "x64" ], @@ -287,9 +287,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.12.tgz", - "integrity": "sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.15.tgz", + "integrity": "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==", "cpu": [ "arm64" ], @@ -305,9 +305,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.12.tgz", - "integrity": "sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.15.tgz", + "integrity": "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==", "cpu": [ "arm64" ], @@ -323,9 +323,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.12.tgz", - "integrity": "sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.15.tgz", + "integrity": "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==", "cpu": [ "x64" ], @@ -854,9 +854,9 @@ } }, "node_modules/postcss": { - "version": "8.5.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", - "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", + "version": "8.5.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz", + "integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==", "dev": true, "funding": [ { @@ -875,7 +875,7 @@ "license": "MIT", "peer": true, "dependencies": { - "nanoid": "^3.3.19", + "nanoid": "^3.3.20", "picocolors": "^1.1.1", "source-map-js": "^1.2.2" }, @@ -884,14 +884,14 @@ } }, "node_modules/rolldown": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.12.tgz", - "integrity": "sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.15.tgz", + "integrity": "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@oxc-project/types": "=0.152.0", + "@oxc-project/types": "=0.155.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -901,21 +901,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm-eabi": "1.2.12", - "@rolldown/binding-android-arm64": "1.2.12", - "@rolldown/binding-darwin-arm64": "1.2.12", - "@rolldown/binding-darwin-x64": "1.2.12", - "@rolldown/binding-freebsd-x64": "1.2.12", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.12", - "@rolldown/binding-linux-arm64-gnu": "1.2.12", - "@rolldown/binding-linux-arm64-musl": "1.2.12", - "@rolldown/binding-linux-ppc64-gnu": "1.2.12", - "@rolldown/binding-linux-s390x-gnu": "1.2.12", - "@rolldown/binding-linux-x64-gnu": "1.2.12", - "@rolldown/binding-linux-x64-musl": "1.2.12", - "@rolldown/binding-openharmony-arm64": "1.2.12", - "@rolldown/binding-win32-arm64-msvc": "1.2.12", - "@rolldown/binding-win32-x64-msvc": "1.2.12" + "@rolldown/binding-android-arm-eabi": "1.2.15", + "@rolldown/binding-android-arm64": "1.2.15", + "@rolldown/binding-darwin-arm64": "1.2.15", + "@rolldown/binding-darwin-x64": "1.2.15", + "@rolldown/binding-freebsd-x64": "1.2.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.15", + "@rolldown/binding-linux-arm64-gnu": "1.2.15", + "@rolldown/binding-linux-arm64-musl": "1.2.15", + "@rolldown/binding-linux-ppc64-gnu": "1.2.15", + "@rolldown/binding-linux-s390x-gnu": "1.2.15", + "@rolldown/binding-linux-x64-gnu": "1.2.15", + "@rolldown/binding-linux-x64-musl": "1.2.15", + "@rolldown/binding-openharmony-arm64": "1.2.15", + "@rolldown/binding-win32-arm64-msvc": "1.2.15", + "@rolldown/binding-win32-x64-msvc": "1.2.15" } }, "node_modules/source-map-js": { @@ -988,17 +988,17 @@ } }, "node_modules/vite": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.2.tgz", - "integrity": "sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.5.tgz", + "integrity": "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", - "postcss": "^8.5.28", - "rolldown": "~1.2.11", + "postcss": "^8.5.30", + "rolldown": "~1.2.14", "tinyglobby": "^0.2.17" }, "bin": { @@ -1015,7 +1015,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.7.1", + "@vitejs/devtools": "^0.7.1 || ^0.8.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", diff --git a/packages/synapsis-client/tests/index.test.ts b/packages/synapsis-client/tests/index.test.ts new file mode 100644 index 0000000..9dd5006 --- /dev/null +++ b/packages/synapsis-client/tests/index.test.ts @@ -0,0 +1,67 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { SynapsisClient } from "../src/index"; + +describe("SynapsisClient.callTool", () => { + const fetchMock = vi.fn(); + + beforeEach(() => { + fetchMock.mockReset(); + vi.stubGlobal("fetch", fetchMock); + }); + + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it("sends a JSON-RPC tools/call request and returns the first text result", async () => { + fetchMock.mockResolvedValue({ + json: async () => ({ result: { content: [{ text: "saved" }] } }), + }); + const client = new SynapsisClient({ baseUrl: "https://synapsis.test" }); + + await expect(client.callTool("mem_save", { title: "note" })).resolves.toBe( + "saved" + ); + + expect(fetchMock).toHaveBeenCalledWith( + "https://synapsis.test/message", + expect.objectContaining({ + method: "POST", + headers: { "Content-Type": "application/json" }, + }) + ); + const request = JSON.parse(fetchMock.mock.calls[0][1].body); + expect(request).toEqual({ + jsonrpc: "2.0", + method: "tools/call", + params: { name: "mem_save", arguments: { title: "note" } }, + id: 1, + }); + }); + + it("sends the configured API key as a bearer token", async () => { + fetchMock.mockResolvedValue({ json: async () => ({ result: {} }) }); + const client = new SynapsisClient({ + baseUrl: "https://synapsis.test", + apiKey: "test-key", + }); + + await client.callTool("db_integrity"); + + expect(fetchMock.mock.calls[0][1].headers).toEqual({ + "Content-Type": "application/json", + Authorization: "Bearer test-key", + }); + }); + + it("rejects JSON-RPC errors with the server message", async () => { + fetchMock.mockResolvedValue({ + json: async () => ({ error: { message: "permission denied" } }), + }); + const client = new SynapsisClient(); + + await expect(client.callTool("mem_save")).rejects.toThrow( + "permission denied" + ); + }); +});