From 2af452704fdd0f48d3ebaa2a0bf6dc67cdac610c Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Sun, 2 Aug 2026 11:47:34 +0530 Subject: [PATCH 01/10] fix: clear dependency audit findings and add multi-ecosystem CI Refresh stale lockfiles, bump vulnerable/blocked packages, repair broken builds, and gate future advisories with a weekly audit workflow. Co-authored-by: Cursor --- .github/audit-allowlist.json | 4 + .github/scripts/audit-osv.py | 211 ++ .github/workflows/audit.yml | 437 +++++ bun/starter/bun.lock | 31 + bun/starter/bun.lockb | Bin 4868 -> 0 bytes bun/starter/package-lock.json | 109 -- bun/sync-with-meilisearch/bun.lock | 96 + bun/sync-with-meilisearch/bun.lockb | Bin 12799 -> 0 bytes bun/sync-with-meilisearch/package.json | 6 +- bun/sync-with-meilisearch/src/utils.ts | 4 +- bun/sync-with-qdrant/bun.lock | 161 ++ bun/sync-with-qdrant/bun.lockb | Bin 22884 -> 0 bytes bun/sync-with-qdrant/package.json | 6 +- bun/sync-with-qdrant/src/utils.ts | 4 +- bun/whatsapp-with-vonage/bun.lock | 65 + bun/whatsapp-with-vonage/package.json | 20 + deno/whatsapp-with-vonage/src/main.ts | 2 +- go/discord-command-bot/discord.go | 4 +- go/discord-command-bot/go.mod | 2 +- go/discord-command-bot/go.sum | 4 +- go/discord-command-bot/main.go | 15 +- go/starter/go.mod | 2 +- go/starter/go.sum | 8 +- .../discord-command-bot/package-lock.json | 40 +- .../discord-command-bot/package.json | 2 +- .../github-issue-bot/package-lock.json | 278 +-- node-typescript/starter/package-lock.json | 38 +- .../sync-with-meilisearch/package-lock.json | 50 +- .../sync-with-qdrant/package-lock.json | 346 +++- .../whatsapp-with-vonage/package-lock.json | 324 +--- .../package-lock.json | 14 +- node/censor-with-redact/package-lock.json | 14 +- node/chat-with-anyscale/package-lock.json | 288 ++- .../chat-with-perplexity-ai/package-lock.json | 288 ++- node/database-cleaner/package-lock.json | 13 +- node/discord-command-bot/package-lock.json | 18 +- node/email-contact-form/package-lock.json | 16 +- node/email-contact-form/package.json | 2 +- node/generate-pdf/package-lock.json | 17 +- node/generate-with-fal/package-lock.json | 39 +- node/generate-with-fal/package.json | 2 +- node/generate-with-fal/src/main.js | 4 +- .../generate-with-replicate/package-lock.json | 30 +- .../package-lock.json | 20 +- node/github-issue-bot/package-lock.json | 225 ++- .../package-lock.json | 29 +- .../package-lock.json | 298 ++- .../package-lock.json | 36 +- .../package-lock.json | 29 +- node/password-expiry/package-lock.json | 22 +- node/password-expiry/package.json | 2 +- .../package-lock.json | 20 +- node/payments-with-stripe/package-lock.json | 284 ++- node/prompt-chatgpt/package-lock.json | 282 ++- .../package-lock.json | 1707 ++++++++++------- node/push-notification-with-fcm/package.json | 5 +- node/query-mongo-atlas/package-lock.json | 78 +- node/query-neo4j-auradb/package-lock.json | 54 +- node/query-neon-postgres/package-lock.json | 7 +- node/query-redis-labs/package-lock.json | 50 +- node/query-upstash-vector/package-lock.json | 7 +- node/rag-with-langchain/README.md | 2 +- node/rag-with-langchain/package-lock.json | 1025 +++------- node/rag-with-langchain/package.json | 10 +- node/rag-with-langchain/src/main.js | 4 +- node/slack-command-bot/package-lock.json | 16 +- node/slack-command-bot/package.json | 3 - node/slack-command-bot/src/utils.js | 2 +- node/speak-with-elevenlabs/README.md | 10 + node/speak-with-elevenlabs/package-lock.json | 494 +---- node/speak-with-elevenlabs/package.json | 2 +- node/speak-with-elevenlabs/src/main.js | 25 +- node/speak-with-lmnt/package-lock.json | 236 ++- .../package-lock.json | 29 +- node/starter/package-lock.json | 13 +- node/storage-cleaner/package-lock.json | 36 +- .../package-lock.json | 20 +- .../package-lock.json | 284 ++- node/sync-with-algolia/package-lock.json | 223 ++- node/sync-with-meilisearch/package-lock.json | 37 +- node/sync-with-pinecone/package-lock.json | 374 +++- node/sync-with-qdrant/package-lock.json | 724 ++++++- .../package-lock.json | 23 +- .../package-lock.json | 29 +- node/url-shortener/package-lock.json | 20 +- node/whatsapp-with-vonage/package-lock.json | 79 +- php/whatsapp-with-vonage/composer.json | 2 +- 87 files changed, 6293 insertions(+), 3598 deletions(-) create mode 100644 .github/audit-allowlist.json create mode 100755 .github/scripts/audit-osv.py create mode 100644 .github/workflows/audit.yml create mode 100644 bun/starter/bun.lock delete mode 100755 bun/starter/bun.lockb delete mode 100644 bun/starter/package-lock.json create mode 100644 bun/sync-with-meilisearch/bun.lock delete mode 100755 bun/sync-with-meilisearch/bun.lockb create mode 100644 bun/sync-with-qdrant/bun.lock delete mode 100755 bun/sync-with-qdrant/bun.lockb create mode 100644 bun/whatsapp-with-vonage/bun.lock create mode 100644 bun/whatsapp-with-vonage/package.json diff --git a/.github/audit-allowlist.json b/.github/audit-allowlist.json new file mode 100644 index 00000000..7c18ae1a --- /dev/null +++ b/.github/audit-allowlist.json @@ -0,0 +1,4 @@ +{ + "description": "Consciously accepted advisories. Each entry matches by ecosystem + package + advisory id (or CVE). Entries keep the moderate gate from being loosened globally.", + "allowlist": [] +} diff --git a/.github/scripts/audit-osv.py b/.github/scripts/audit-osv.py new file mode 100755 index 00000000..6419eff4 --- /dev/null +++ b/.github/scripts/audit-osv.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 +"""Query the OSV API for Maven (deps.gradle) and Deno URL-pinned dependencies. + +Exits non-zero if any unallowlisted vulnerability at moderate+ severity is found. +Writes a markdown summary to $GITHUB_STEP_SUMMARY when set. +""" + +from __future__ import annotations + +import json +import os +import re +import sys +import urllib.error +import urllib.request +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +ALLOWLIST_PATH = ROOT / ".github" / "audit-allowlist.json" +OSV_QUERY = "https://api.osv.dev/v1/query" +SEVERITY_RANK = {"CRITICAL": 4, "HIGH": 3, "MODERATE": 2, "MEDIUM": 2, "LOW": 1, "UNKNOWN": 2} +MIN_RANK = SEVERITY_RANK["MODERATE"] + + +def load_allowlist() -> set[tuple[str, str, str]]: + if not ALLOWLIST_PATH.exists(): + return set() + data = json.loads(ALLOWLIST_PATH.read_text()) + allowed = set() + for entry in data.get("allowlist", []): + allowed.add( + ( + entry.get("ecosystem", "").lower(), + entry.get("package", "").lower(), + entry.get("id", "").upper(), + ) + ) + return allowed + + +def osv_query(ecosystem: str, name: str, version: str) -> list[dict]: + payload = json.dumps( + {"package": {"ecosystem": ecosystem, "name": name}, "version": version} + ).encode() + req = urllib.request.Request( + OSV_QUERY, + data=payload, + headers={"Content-Type": "application/json"}, + method="POST", + ) + try: + with urllib.request.urlopen(req, timeout=30) as resp: + data = json.loads(resp.read().decode()) + except urllib.error.HTTPError as exc: + print(f"OSV query failed for {ecosystem}:{name}@{version}: {exc}", file=sys.stderr) + return [] + return data.get("vulns", []) + + +def severity_of(vuln: dict) -> str: + for sev in vuln.get("severity", []) or []: + score = sev.get("score") or "" + # CVSS strings like "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + if isinstance(score, str) and "CVSS" in score: + # Rough bucket from base score if present elsewhere + pass + db = vuln.get("database_specific") or {} + sev = (db.get("severity") or db.get("cvss_severity") or "").upper() + if sev in SEVERITY_RANK: + return sev + # Fall back to CVSS score buckets when available + for sev in vuln.get("severity", []) or []: + try: + # Some advisories put numeric score under severity[].score as float-like + numeric = float(str(sev.get("score", "")).split("/")[0]) + if numeric >= 9.0: + return "CRITICAL" + if numeric >= 7.0: + return "HIGH" + if numeric >= 4.0: + return "MODERATE" + if numeric > 0: + return "LOW" + except (TypeError, ValueError): + continue + return "UNKNOWN" + + +def is_allowlisted(allowlist: set, ecosystem: str, package: str, vuln_id: str) -> bool: + eco = ecosystem.lower() + pkg = package.lower() + vid = vuln_id.upper() + return (eco, pkg, vid) in allowlist or (eco, pkg, "") in allowlist + + +def find_maven_coords() -> list[tuple[str, str, str, str]]: + """Return (template, ecosystem, name, version) for deps.gradle files.""" + results = [] + pattern = re.compile( + r"""['"](?P[\w.\-]+):(?P[\w.\-]+):(?P[\w.\-+]+)['"]""" + ) + for path in sorted(ROOT.glob("*/*/deps.gradle")): + text = path.read_text() + template = str(path.parent.relative_to(ROOT)) + for match in pattern.finditer(text): + name = f"{match.group('group')}:{match.group('artifact')}" + results.append((template, "Maven", name, match.group("version"))) + return results + + +def find_deno_coords() -> list[tuple[str, str, str, str]]: + """Map Deno URL pins to OSV npm/JSR queries where possible.""" + results = [] + url_re = re.compile( + r"""https://(?:esm\.sh|cdn\.skypack\.dev)/(?P@?[^@/"']+)@(?P[^/"']+)""" + ) + deno_land_re = re.compile( + r"""https://deno\.land/(?:x|std)@?(?P[^@/"']*)@(?P[^/"']+)""" + ) + jose_re = re.compile( + r"""https://deno\.land/x/jose@(?P[^/"']+)""" + ) + appwrite_re = re.compile( + r"""https://deno\.land/x/appwrite@(?P[^/"']+)""" + ) + + for path in sorted((ROOT / "deno").glob("*/src/**/*.ts")): + text = path.read_text() + template = str(path.parents[1].relative_to(ROOT)) if path.parents[1].name != "src" else str(path.parent.parent.relative_to(ROOT)) + # Prefer template root: deno/