# JetBrains Marketplace API notes Reference notes for `scanners/lib/vsix-fetch.mjs` and `scanners/lib/jetbrains-fetch-worker.mjs`. These endpoints are used to download JetBrains plugin archives for `/security ide-scan ` (v6.6.0). ## Base URL ``` https://plugins.jetbrains.com/ ``` ## Metadata lookup ``` GET https://plugins.jetbrains.com/api/plugins/{numericId} GET https://plugins.jetbrains.com/api/plugins/{numericId}/updates?size=N ``` - `{numericId}` is an integer assigned by JetBrains when the plugin is first published. It is the first path segment (before the dash) in the user-facing URL — e.g. `https://plugins.jetbrains.com/plugin/7973-intellivue` → numericId `7973`, slug `intellivue`. - `GET /api/plugins/{numericId}` returns plugin metadata including `xmlId` (the `` from `plugin.xml`), `name`, `vendor.name`, `vendor.isVerified`, `programmingLanguage`, `urls`. We use this only when `--online` is set, and never trust `vendor.isVerified` as a safety signal — it attests publisher identity, not plugin safety (see OX Security 2025). - `GET /api/plugins/{numericId}/updates?size=N` returns the last N versions with `id`, `version`, `cdate` (unix millis), `file` (CDN path), and `recommended`. We use this to resolve "latest stable" without trusting the plugin page HTML. ## Direct download Two equivalent URL shapes, both officially supported: ``` GET https://plugins.jetbrains.com/pluginManager?action=download&id={xmlId}&build={productCode}-{buildNumber} GET https://plugins.jetbrains.com/plugin/download?pluginId={xmlId}&version={v} ``` - `action=download` is what the IntelliJ IDE itself uses via its plugin manager. `{productCode}` is `IC` (IDEA Community), `IU` (IDEA Ultimate), `PY`, `PS`, `GO`, `RD`, `CL`, `WS`, `RM`, `DB`, etc. `{buildNumber}` is a short build string like `241.18034.62`. When both are present, the server returns the compatible version; otherwise it returns a 400. - `plugin/download?pluginId={xmlId}&version={v}` is stable and simpler — we prefer this shape when the caller passes `?version=`. If no version is given we resolve `latest` via the `updates` endpoint first, then request that version explicitly. - The response is a ZIP (or in rare legacy cases a JAR). `Content-Type` is `application/octet-stream` or `application/java-archive`. The fetcher tolerates both. ## Redirect host whitelist The JetBrains CDN reroutes downloads. Our fetcher (`vsix-fetch.mjs`) accepts redirects only to: - `plugins.jetbrains.com` - `downloads.marketplace.jetbrains.com` - `cache-redirector.jetbrains.com` Any other host aborts with `Error: redirect not allowed: ` and the worker exits non-zero. This matches the VS Code Marketplace redirect policy in `marketplace-api-notes.md`. ## URL-to-numericId resolution `detectUrlType` accepts three JetBrains URL shapes: ``` https://plugins.jetbrains.com/plugin/{numericId}-{slug} https://plugins.jetbrains.com/plugin/{numericId}-{slug}/versions/{version} https://plugins.jetbrains.com/pluginManager?action=download&id={xmlId} https://plugins.jetbrains.com/plugin/download?pluginId={xmlId} ``` For the first two, we split the first path segment on `-` and take the leading integer as `numericId`. For the `action=download` / `download?pluginId` forms we pass the URL through directly. ## Rate limits JetBrains publishes no explicit rate limit. Observed in the field: low-tens of requests per minute per IP is safe. Our default is 1 req/s (conservative) — we issue at most three requests per URL scan (metadata + updates + download) so rate budget is generous. ## Caps & defenses (shared with VS Code fetcher) - TLS verification enabled (no `--insecure` opt-in). - HTTPS only. Plain HTTP is rejected at `detectUrlType` and at fetch time. - Manual redirect handling. Allowed hosts whitelisted per source type. - 30-second total timeout via `AbortController`. - 50MB compressed archive cap. Streaming reader aborts when cap exceeded. - SHA-256 computed during streaming for `meta.source.sha256`. ## What is NOT supported (v6.6.0) - No equivalent of OpenVSX — JetBrains Marketplace is the only distribution channel, so URL scans fall through to direct-URL VSIX rules if the caller passes a raw `.zip` or `.jar` URL on any other host. - Custom plugin repositories (`updatePlugins.xml` feeds on self-hosted servers) are out of scope. A target like `https://my-repo.example.com/updatePlugins.xml` is not a plugin archive and will fail `detectUrlType`. - Archive signature verification — JetBrains ships plugins unsigned by default; the Marketplace signs metadata at publish time but the ZIP itself carries no embedded signature we can verify offline. ## References - JetBrains plugin-content — https://plugins.jetbrains.com/docs/intellij/plugin-content.html - JetBrains plugin-configuration-file — https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html - JetBrains Marketplace REST (informal) — https://plugins.jetbrains.com/docs/marketplace/api.html - YouTrack IJPL-212393 — signature-warning inconsistency - OX Security 2025 — JetBrains verified-badge bypass