Skip to content

fix(audit-deps): severidad de origen, dedupe de conteos y estado INCOMPLETE explicito - #5

Open
javier20dev25 wants to merge 4 commits into
masterfrom
fix/audit-deps-severity-coverage
Open

javier20dev25 wants to merge 4 commits into
masterfrom
fix/audit-deps-severity-coverage

Conversation

@javier20dev25

Copy link
Copy Markdown
Owner

Problema

sentinel audit-deps reportaba todos los hallazgos de dependencias como MEDIUM, independientemente de la severidad publicada por OSV/GHSA.

Causa raíz (dos bugs encadenados)

  1. OSVIntegrator.queryBatch usa POST /v1/querybatch, que devuelve solo stubs (id + modified), sin severity, database_specific ni affected. Nunca se traía la severidad real.
  2. Aun cuando hubiera vector, getMaxSeverity hacía parseFloat(s.score) sobre un vector CVSS ("CVSS:3.1/AV:N/...") → NaN → null → el caller aplicaba el default 'MEDIUM'.

Evidencia (lockfile controlado, 2 paquetes): antes → 19 findings, todos MEDIUM; las fuentes publican HIGH / MODERATE / LOW.

Cambios

  • Hidratación OSV: tras el batch, se resuelve cada aviso único vía GET /v1/vulns/{id} (dedupe por ID, concurrencia 8). Ahora hay severidad, affected y fixed.
  • Severidad de origen (sourceSeverity): de database_specific.severity; si falta, del vector CVSS v3.0/3.1 (score local); si es v4.0 se registra el vector pero queda UNKNOWN (no se inventa). Se guarda sourceSeveritySource (procedencia) y sentinelSeverity (severityMapping).
  • Nunca fabricar severidad: sin dato → UNKNOWN, jamás MEDIUM.
  • Conteos deduplicados: instances (ocurrencias crudas) vs pkgVersionGhsa (único paquete@versión:aviso) vs uniqueGhsa (avisos únicos). Las distribuciones de severidad se calculan sobre avisos únicos.
  • Estado explícito INCOMPLETE: pnpm / Yarn Berry / sin lockfile / parse de 0 deps → status: "INCOMPLETE" + coverageReason, y exit 2 bajo --ci (antes: exit 0 silencioso, indistinguible de “limpio”).
  • Fix de remediación por aviso: fixedVersions sale de cada advisory, no de una versión asumida por paquete.
  • Se propaga a CLI y MCP.

Verificación

  • tsc --noEmit limpio.
  • vitest: 35/35 en supply_chain_a2.test.ts (nuevos tests: parseo de vector, severidad de origen, dedupe). Suite completa: 1363 pasan; 2 fallos preexistentes y ajenos (src/core/network/captureBuildIdentity, timeout 30s).
  • E2E lockfile controlado → HIGH 10 / MEDIUM 6 / LOW 3, con CVEs y fixedVersions correctos.
  • E2E --ci --json con pnpm-lock.yaml y Yarn Berry → status: INCOMPLETE, exit 2.

Gates cubiertos

Gate Estado
Sin cobertura ≠ KNOWN_SAFE ✅ INCOMPLETE explícito
GHSA ↔ paquete/versión reproducible ✅ findings[] con fixedVersions
Datos sin severidad señalados ✅ UNKNOWN + sourceSeveritySource
Mismo GHSA en varias versiones ≠ avisos únicos ✅ uniqueGhsa vs instances
Error de parser ≠ ausencia de vulns ✅ INCOMPLETE + exit 2
No modificar repos/lockfiles auditados ✅ solo lectura

Pendiente (fuera de este PR)

Parsers nativos de pnpm-lock.yaml y Yarn Berry (hoy INCOMPLETE); y re-medir el benchmark con casos controlados antes de calcular precisión/cobertura.

…COMPLETE status

- OSV /querybatch returns only advisory stubs (id+modified); hydrate each
  unique advisory via /v1/vulns/{id} so published severity and fixed versions
  are actually available. Previously parseFloat(vector)=NaN defaulted every
  finding to MEDIUM.
- Add source severity extraction (database_specific.severity, else CVSS v3.x
  vector score) and record provenance; never fabricate a level (UNKNOWN).
- Separate counts: instances vs package@version x advisory vs unique advisories;
  severity distributions computed over unique advisories.
- Emit explicit INCOMPLETE (unsupported pnpm/Yarn Berry, missing lockfile,
  0-dependency parse) with coverageReason; exit 2 under --ci instead of a
  misleading clean result.
- Wire through CLI and MCP; add tests for vector parsing, source severity and
  dedupe counters.
…hed @sentinel/cli

The audit job failed on every PR with npm 404 because it ran

pm install -g @sentinel/cli@latest, but no such package exists (the repo
package is sntnl-cli). The installed binary is also sntnl, not sentinel.

Build and install the CLI from the checked-out repository so the PR is audited
with the branch's own code, and invoke the correct sntnl binary.
@github-actions

Copy link
Copy Markdown

🟢 Sentinel PR Audit — Approved

Action: SAFE TO PROCEED — No security threats detected.

Repository javier20dev25/sentinel-cli
PR #5 by javier20dev25
Files Analyzed 13
Total Findings 2
Risk Band SAFE
Decision PASS

🔵 LOW (2)

dist/cli/intelligence/osv_integrator.js:149 — NETWORK_ACTIVITY

Detection: Outbound network communication detected.
Risk: Makes outbound HTTP/HTTPS requests. Can exfiltrate secrets, download payloads, or phone home to a C2 server.

const response = yield fetch(`${OSVIntegrator.VULN_API_URL}/${encodeURIComponent(id)}`, {
src/cli/intelligence/osv_integrator.ts:172 — NETWORK_ACTIVITY

Detection: Outbound network communication detected.
Risk: Makes outbound HTTP/HTTPS requests. Can exfiltrate secrets, download payloads, or phone home to a C2 server.

const response = await fetch(`${OSVIntegrator.VULN_API_URL}/${encodeURIComponent(id)}`, {

Scanned by Sentinel CLI | Hash: 8f4f622ba783

Parse pnpm-lock.yaml (lockfileVersion 5/6/9, importers/packages/snapshots)
and Yarn Berry yarn.lock (__metadata) into the unified LockfileEntry
shape so audit-deps can analyze them instead of emitting INCOMPLETE.

Keep the INCOMPLETE contract for truly unparseable files.
@github-actions

Copy link
Copy Markdown

🟢 Sentinel PR Audit — Approved

Action: SAFE TO PROCEED — No security threats detected.

Repository javier20dev25/sentinel-cli
PR #5 by javier20dev25
Files Analyzed 13
Total Findings 2
Risk Band SAFE
Decision PASS

🔵 LOW (2)

dist/cli/intelligence/osv_integrator.js:149 — NETWORK_ACTIVITY

Detection: Outbound network communication detected.
Risk: Makes outbound HTTP/HTTPS requests. Can exfiltrate secrets, download payloads, or phone home to a C2 server.

const response = yield fetch(`${OSVIntegrator.VULN_API_URL}/${encodeURIComponent(id)}`, {
src/cli/intelligence/osv_integrator.ts:172 — NETWORK_ACTIVITY

Detection: Outbound network communication detected.
Risk: Makes outbound HTTP/HTTPS requests. Can exfiltrate secrets, download payloads, or phone home to a C2 server.

const response = await fetch(`${OSVIntegrator.VULN_API_URL}/${encodeURIComponent(id)}`, {

Scanned by Sentinel CLI | Hash: 261606d688e9

@github-actions

Copy link
Copy Markdown

🟢 Sentinel PR Audit — Approved

Action: SAFE TO PROCEED — No security threats detected.

Repository javier20dev25/sentinel-cli
PR #5 by javier20dev25
Files Analyzed 14
Total Findings 2
Risk Band SAFE
Decision PASS

🔵 LOW (2)

dist/cli/intelligence/osv_integrator.js:149 — NETWORK_ACTIVITY

Detection: Outbound network communication detected.
Risk: Makes outbound HTTP/HTTPS requests. Can exfiltrate secrets, download payloads, or phone home to a C2 server.

const response = yield fetch(`${OSVIntegrator.VULN_API_URL}/${encodeURIComponent(id)}`, {
src/cli/intelligence/osv_integrator.ts:172 — NETWORK_ACTIVITY

Detection: Outbound network communication detected.
Risk: Makes outbound HTTP/HTTPS requests. Can exfiltrate secrets, download payloads, or phone home to a C2 server.

const response = await fetch(`${OSVIntegrator.VULN_API_URL}/${encodeURIComponent(id)}`, {

Scanned by Sentinel CLI | Hash: ee2357471cde

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant