bumblebee README

The project's README from github.com/perplexityai/bumblebee. As one markdown file: README.md.

bumblebee

Bumblebee is a read-only inventory collector for package, extension, and developer-tool metadata on macOS and Linux developer endpoints.

It answers a narrow supply-chain response question: when an advisory names a package, extension, or version, which developer machines show a match in their on-disk metadata right now?

SBOMs help answer what shipped, and EDR helps answer what ran or touched the network, but supply-chain response often needs a different view: messy local state across lockfiles, package-manager metadata, extension manifests, and supported developer-tool configs.

Bumblebee turns that scattered on-disk state into structured NDJSON component records and, when given an exposure catalog, flags exact matches for fast, read-only exposure checks when responders already know what they are looking for.

Scope

Coverage

Family Emitted ecosystem Sources
npm npm package-lock.json, npm-shrinkwrap.json, node_modules/.package-lock.json, node_modules/<pkg>/package.json
pnpm npm pnpm-lock.yaml, .pnpm/.../package.json
Yarn npm yarn.lock (Classic + Berry)
Bun npm bun.lock; bun.lockb presence as diagnostic
PyPI pypi *.dist-info/METADATA, INSTALLER, direct_url.json, *.egg-info/PKG-INFO
Go modules go go.sum, go.mod
RubyGems rubygems Gemfile.lock, installed *.gemspec
Composer packagist composer.lock, vendor/composer/installed.json
MCP mcp JSON host configs: mcp.json, .mcp.json, claude_desktop_config.json, mcp_config.json, mcp_settings.json, cline_mcp_settings.json, plus ~/.gemini/settings.json (Gemini CLI / Code Assist) and ~/.claude.json (Claude Code user- and project-scoped mcpServers). Non-JSON configs (Codex config.toml, Continue YAML) are not parsed in v0.1.
Agent skills agent-skill skills.sh / vercel-labs/skills lock files: global ~/.agents/.skill-lock.json (or $XDG_STATE_HOME/skills/.skill-lock.json) and project-local skills-lock.json. Loose SKILL.md directories without a lock file are not enumerated.
Editor extensions editor-extension VS Code, Cursor, Windsurf, VSCodium manifests
Browser extensions browser-extension Chromium-family (manifest.json) and Firefox (extensions.json) per profile
Homebrew homebrew Formula INSTALL_RECEIPT.json files and cask .metadata install markers

Per-ecosystem detail: docs/inventory-sources.md.

Install

Requires Go 1.25+. Zero non-stdlib dependencies.

# Install the latest tagged release into $GOBIN.
go install github.com/perplexityai/bumblebee/cmd/bumblebee@latest

# Or pin a specific tag.
go install github.com/perplexityai/bumblebee/cmd/[email protected]

To build from a checkout:

go build -o bumblebee ./cmd/bumblebee
go test ./...

Stamp an explicit version at build time:

go build -ldflags "-X main.Version=v0.1.1" -o bumblebee ./cmd/bumblebee

bumblebee version prints the version plus the VCS revision, build time, and Go runtime — so a record emitted in production can be traced back to a specific build. Version precedence: -ldflags override, module version recorded by go install, then the in-tree default tracked in VERSION.

Self-test

After installing, run a built-in end-to-end check against embedded fixtures:

bumblebee selftest
# selftest OK (2 findings in 1ms)

The fixtures live inside the binary, use deliberately fake package names ([email protected]), and make no network calls. A non-zero exit means the local install can no longer detect what it should — a fast pre-deployment smoke test for fleet rollouts.

Profiles

Bumblebee is a one-shot scanner: each invocation performs a single scan and exits. Cadence is the runner's responsibility (cron, launchd, systemd, MDM, etc.). Each record carries profile and a per-root root_kind so receivers can keep populations separate.

Profile Scans Use for
baseline Common global/user package roots, language toolchains, editor extensions, browser extensions, and MCP configs. Recurring lightweight inventory via an external runner.
project Configured development directories, such as ~/code, ~/src, or ~/work. Recurring inventory for known project workspaces.
deep Explicit --root paths, including broad roots like $HOME. On-demand incident or campaign checks, usually with --ecosystem, --exposure-catalog, and --findings-only.

baseline and project refuse bare-home roots; only deep walks them.

Quick start

# Baseline global inventory.
bumblebee scan --profile baseline > inventory.ndjson

# Daily project sweep with explicit roots.
bumblebee scan --profile project \
  --root "$HOME/code" \
  --root "$HOME/Developer"

# Limit a run to selected emitted ecosystems.
bumblebee scan --profile baseline \
  --ecosystem npm,pypi \
  --ecosystem go

# On-demand exposure scan against a published advisory.
bumblebee scan --profile deep \
  --root "$HOME" \
  --exposure-catalog ./catalog.json \
  --max-duration 10m

Preview the resolved roots without scanning:

bumblebee roots --profile baseline
# prints "<root_kind>\t<path>" lines

--root is a filesystem path to scan; repeatable, required for deep, optional for the other profiles. --ecosystem is repeatable and comma-separated. --exposure-catalog accepts a JSON file or a directory of *.json catalogs (merged non-recursively, all files must share schema_version). --findings-only requires --exposure-catalog and suppresses package records while keeping findings. bumblebee scan --help lists every flag.

Output

Records are NDJSON, one per line. Diagnostics go to stderr as NDJSON. Each run ends with a scan_summary record; receivers use it to decide whether to promote a run to current state. See docs/transport.md for HTTPS/file output and docs/state-model.md for the receiver-side current-state model.

Package record:

Example package record
{
  "record_type": "package",
  "record_id": "package:...",
  "schema_version": "0.2.0",
  "scanner_name": "bumblebee",
  "scanner_version": "v0.1.1",
  "run_id": "9b1f0c2e4d5a6b7c8d9e0f1a2b3c4d5e",
  "scan_time": "2026-05-15T18:22:01.482Z",
  "endpoint": {
    "hostname": "alex-mbp",
    "os": "darwin",
    "arch": "arm64",
    "username": "alex",
    "uid": "501",
    "device_id": "MDM-7F4A2B"
  },
  "profile": "project",
  "ecosystem": "npm",
  "package_name": "@tanstack/query-core",
  "normalized_name": "@tanstack/query-core",
  "version": "5.59.20",
  "project_path": "/Users/alex/code/web-app",
  "root_kind": "project_root",
  "package_manager": "pnpm",
  "source_type": "pnpm-lockfile",
  "source_file": "/Users/alex/code/web-app/pnpm-lock.yaml",
  "has_lifecycle_scripts": false,
  "confidence": "high"
}

confidence:

Finding record (exposure-catalog match):

Example finding record
{
  "record_type": "finding",
  "record_id": "finding:...",
  "schema_version": "0.2.0",
  "scanner_name": "bumblebee",
  "scanner_version": "v0.1.1",
  "run_id": "3a8c7d1e9f0b2a4c6d8e0f1a2b3c4d5e",
  "scan_time": "2026-05-15T18:22:01.482Z",
  "endpoint": {
    "hostname": "alex-mbp",
    "os": "darwin",
    "arch": "arm64",
    "username": "alex",
    "uid": "501",
    "device_id": "MDM-7F4A2B"
  },
  "profile": "deep",
  "finding_type": "package_exposure",
  "severity": "critical",
  "catalog_id": "advisory-2026-0042",
  "catalog_name": "example-pkg 1.2.3 (compromised release)",
  "ecosystem": "npm",
  "package_name": "example-pkg",
  "normalized_name": "example-pkg",
  "version": "1.2.3",
  "root_kind": "deep_home_root",
  "project_path": "/Users/alex/code/web-app",
  "source_type": "pnpm-lockfile",
  "source_file": "/Users/alex/code/web-app/pnpm-lock.yaml",
  "confidence": "high",
  "evidence": "exact name+version match (version=1.2.3)"
}

record_id is a content-addressed hash of a canonical identity tuple per record type, stable across runs. Per-record-type field lists and dedupe guidance: docs/state-model.md.

Exposure Catalog Format

Minimal JSON, exact (ecosystem, name, version) matching. An entry may declare "versions": ["*"] to match every version of the package:

{
  "schema_version": "0.2.0",
  "entries": [
    {
      "id": "advisory-2026-0042",
      "name": "example-pkg 1.2.3 (compromised release)",
      "ecosystem": "npm",
      "package": "example-pkg",
      "versions": ["1.2.3"],
      "severity": "critical"
    }
  ]
}

The catalog must be a JSON object with schema_version and entries keys. Bare top-level arrays are rejected. schema_version 0.1.0 catalogs are still accepted (they cannot use "*"); unsupported future values are rejected. Multiple catalog files can be loaded together by pointing --exposure-catalog at a directory; see the flag description above.

Sample exposure catalogs

The threat_intel/ directory holds maintained exposure catalogs built from public threat-intelligence reporting on recent supply-chain campaigns, assembled with Perplexity Computer and updated via PRs as new campaigns are reported. See threat_intel/README.md for the current catalog list and review guidance.

License

Apache License 2.0. See LICENSE.

bumblebee (perplexityai/bumblebee)

Searching Database…

这是什么?Bumblebee 是一个只读的清单收集工具,用于扫描 macOS 和 Linux 开发者机器上的软件包、扩展和开发工具元数据,帮助应急响应人员快速检查机器是否符合已知的供应链入侵通告。
这是会修改系统的扫描器,还是只读取文件?它严格只读:只解析磁盘上的锁文件、包管理器元数据、扩展清单以及受支持的 MCP JSON 配置。它从不运行 npm ls 或 pip show 之类的包管理器命令,也从不读取源代码文件。
如何运行扫描?从代码检出目录构建单个静态 Go 二进制文件,然后使用 baseline、project 或 deep 三种配置之一运行 `bumblebee scan`;`--root` 用于为 deep 配置指定扫描路径。正式扫描前,你可以先预览解析后的根目录,运行 `bumblebee scan --help` 可列出所有参数。
构建时除了 Go 还需要安装其他东西吗?只需要 Go 1.25+;该二进制文件不依赖任何标准库之外的组件,因此无需再安装其他东西。
它不读取哪些文件格式或配置?在 v0.1 版本中,不解析非 JSON 格式的智能体配置,例如 Codex 的 config.toml 和 Continue 的 YAML 文件;没有锁文件的零散 SKILL.md 目录也不会被枚举。
到底谁在用这个工具,什么时候用?它面向事件响应人员和安全团队,用于供应链暴露排查:baseline 和 project 配置通过 cron、launchd 或 systemd 定期运行轻量级清单收集,而 deep 配置用于按需进行的事件或针对性攻击活动调查。
它能扫描哪些操作系统?macOS 和 Linux 开发者终端;baseline 和 project 配置会拒绝直接以主目录本身为根进行遍历的路径,只有 deep 配置可以。
它会泄露所读取的 MCP 配置中的机密信息吗?MCP 宿主配置的 env 块中可能包含凭据,但 Bumblebee 只解析服务器清单所需的内容,不会在其输出记录中输出这些机密值。
它覆盖哪些生态系统和包管理器?npm、pnpm、Yarn、Bun、PyPI、Go 模块、RubyGems、Composer、Homebrew、MCP 服务器配置、智能体技能锁文件、编辑器扩展(VS Code、Cursor、Windsurf、VSCodium),以及 Chromium 和 Firefox 浏览器扩展。
它如何检查机器是否暴露于已知存在漏洞的软件包?你需要提供一个暴露目录(包含 schemaVersion 和 entries 的 JSON 文件,entries 列出生态系统、名称和版本),bumblebee 会将其与磁盘上的元数据进行精确匹配并标记;使用 '--findings-only' 会隐藏普通软件包记录,只显示匹配结果。
扫描输出如何为自动化处理而格式化?输出为 NDJSON 格式,每行一条 JSON 记录;诊断信息输出到 stderr,每次运行结束时输出一条 scanSummary 记录,以便接收端判断是否将本次运行结果提升为当前状态。
部署前如何验证安装是否正常工作?运行内置的自检功能,针对内嵌的测试数据进行检测,其中包含刻意虚构的软件包名称,且不进行任何网络调用;如果退出码非零,说明安装无法正确检测应当识别的内容,这可以作为部署前很有用的冒烟测试。
Size
0.2 MB
Stars
5.1K
Age
4mo
Commits · 90 Days