@peachstudio/synapse-sbom
v0.1.1
Published
SYNAPSE SBOM scanner for npm projects — generate a CycloneDX SBOM locally and submit it to SYNAPSE Software Component Analysis.
Maintainers
Readme
@peachstudio/synapse-sbom
Command:
synapse-sbom· npm package:@peachstudio/synapse-sbom
Generate a CycloneDX 1.6 SBOM from your npm project locally and submit it to SYNAPSE Software Component Analysis (SCA). Vulnerable components are then continuously re-evaluated as new advisories land — scan once, monitored forever.
- Zero runtime dependencies. Node ≥ 18.
- The SBOM is built on your machine; only the SBOM JSON leaves it.
- Re-scans update the same product (stable project identity), so history and continuous monitoring survive renames and CI re-runs.
Quick start
# 1. Create an API key in the SYNAPSE webapp (see "Authentication" below):
# Settings → Security → API Keys → name it → Create → copy the syn_… key
# 2. Store it once (written to ~/.config/synapse-sbom/config.json, mode 600):
npx @peachstudio/synapse-sbom login --key syn_xxxxxxxxxxxx
# 3. From your project root (needs package.json + package-lock.json):
npx @peachstudio/synapse-sbom scanThat's it. Output:
Project identity: git:github.com/acme/web (git remote)
Generated CycloneDX SBOM: [email protected] (412 components)
Submitting 412 component(s) to https://api.synapse-intel.com …
Done in 7s (HTTP 200)
Submitted to https://api.synapse-intel.com
product : acme-web (d51e5833-…)
components : 412
vulnerable : 5
new CVEs : 2Install it instead of using npx if you prefer (the installed command is
synapse-sbom):
npm i -g @peachstudio/synapse-sbom # global CLI → `synapse-sbom`
npm i -D @peachstudio/synapse-sbom # or as a dev dependency, run via npm scriptsCommand reference
Copy-paste, no install needed (npx). If installed globally, drop the
npx @peachstudio/synapse-sbom prefix and just use synapse-sbom.
# Authenticate once — key stored 0600 at ~/.config/synapse-sbom/config.json
npx @peachstudio/synapse-sbom login --key syn_xxx --url https://api.synapse-intel.com
npx @peachstudio/synapse-sbom login # interactive hidden prompt
# Scan
npx @peachstudio/synapse-sbom scan # current project, submit
npx @peachstudio/synapse-sbom scan ./path/to/app # a specific project
npx @peachstudio/synapse-sbom scan --dry-run # print SBOM only, no upload, no side effects
npx @peachstudio/synapse-sbom scan --product my-svc # override display name
npx @peachstudio/synapse-sbom scan --project my-key # explicit stable project key
# Per-run auth/endpoint overrides (skip stored config)
npx @peachstudio/synapse-sbom scan --url https://api.synapse-intel.com --key syn_xxx
SYNAPSE_API_KEY=syn_xxx SYNAPSE_API_URL=https://api.synapse-intel.com \
npx @peachstudio/synapse-sbom scan
# Local SYNAPSE instead of prod
npx @peachstudio/synapse-sbom scan --url http://localhost:8085 --key syn_local
# Inspect resolved URL / masked key / config path
npx @peachstudio/synapse-sbom whoami
# Help
npx @peachstudio/synapse-sbom help| Flag | Env | Default | Meaning |
|---|---|---|---|
| --key | SYNAPSE_API_KEY | stored config | Bearer API key |
| --url | SYNAPSE_API_URL | https://api.synapse-intel.com | SCA API base URL |
| --project | SYNAPSE_PROJECT | git remote → generated | Stable project identity (survives renames/CI) |
| --product | — | package.json name | Display name only |
| --dry-run | — | off | Build SBOM, print to stdout, don't upload or write .synapse-sbom.json |
| — | SYNAPSE_TIMEOUT_MS | 1200000 (20 min) | Client request timeout |
| — | SYNAPSE_SBOM_CONFIG_DIR | ~/.config/synapse-sbom | Config directory |
Resolution order (key & URL): flag > env > stored config > default.
Security: the SBOM is built locally; only it (+ a Bearer key over
HTTPS) leaves your machine. The key is never written to the project,
the SBOM, or .synapse-sbom.json. The CLI warns if you point
--url at a plaintext http:// non-local host (cleartext-key risk);
http://localhost and https:// are silent. Exit code 0 on success,
1 on any error (CI-friendly).
Authentication (API key)
Get a key
- Sign in to the SYNAPSE webapp.
- Go to Settings → Security → API Keys. API access requires a Business (up to 5 keys) or Enterprise (up to 20 keys) tier — lower tiers see an upgrade notice and cannot create keys.
- Enter a name (e.g.
ci-sbom) and click Create. - The key (format
syn_+ 32 hex chars) is shown once in a banner — copy it immediately with the copy button. It is not retrievable later; if lost, revoke it and create a new one. Keys can be revoked anytime from the same screen.
Give the key to the scanner
Three ways, highest precedence first (flag → env → stored config):
| Method | How | Best for |
|---|---|---|
| Flag | --key syn_… on login or scan | one-off / overrides |
| Env | SYNAPSE_API_KEY=syn_… | CI (use a secret) |
| Stored config | synapse-sbom login --key syn_… → ~/.config/synapse-sbom/config.json (chmod 600) | local dev machine |
login also stores the API URL. Verify what's resolved at any time:
synapse-sbom whoami
# API URL : https://api.synapse-intel.com
# API key : syn_abc…(36 chars)
# Config : /home/you/.config/synapse-sbom/config.jsonThe key is only ever stored in that 0600 config file (or your env/CI
secret store) — it is never written into your project tree, the SBOM,
or .synapse-sbom.json.
Commands
| Command | What it does |
|---|---|
| synapse-sbom login [--key <k>] [--url <u>] | Store API key (+ URL) to ~/.config/synapse-sbom/config.json (chmod 600). Omit --key for a hidden interactive prompt. |
| synapse-sbom scan [path] | Build a CycloneDX SBOM for path (default .) and submit it. path must contain package.json + package-lock.json. |
| synapse-sbom whoami | Show the resolved API URL, masked key, and config file path. |
| synapse-sbom help | Usage (also shown with no command or --help). |
scan options
| Flag | Env | Default | Meaning |
|---|---|---|---|
| --dry-run | — | off | Print the CycloneDX SBOM to stdout and do not upload. Does not write .synapse-sbom.json. |
| --product <name> | — | package.json name | Override the product display name only (identity is the project key, see below). |
| --project <key> | SYNAPSE_PROJECT | resolved (see below) | Explicit stable project key. |
| --url <url> | SYNAPSE_API_URL | https://api.synapse-intel.com | SCA API base URL. Use --url http://localhost:8085 for a local SYNAPSE. |
| --key <key> | SYNAPSE_API_KEY | stored config | API key for this run (overrides stored config). |
Other environment variables
| Var | Purpose |
|---|---|
| SYNAPSE_TIMEOUT_MS | Client-side request timeout (default 1200000 = 20 min). Large projects resolve server-side; raise this only if you hit a timeout. |
| SYNAPSE_SBOM_CONFIG_DIR | Override the config directory (default $XDG_CONFIG_HOME/synapse-sbom or ~/.config/synapse-sbom). |
Resolution order for API key / URL: flag → env → stored config → default.
Project identity (re-scans update the same product)
Every project gets a stable key so re-scanning always updates the same
product — even after a package.json rename, and identically across every
clone and CI runner. Resolution order:
--project <key>/SYNAPSE_PROJECT- committed
.synapse-sbom.json—{ "projectId": "…" } - the git remote URL, normalized (e.g.
git:github.com/acme/web) - otherwise a UUID is generated and written to
.synapse-sbom.json— commit that file so every clone / CI run scans as the same product.
Server-side identity is (your account, project key); the product name is
just a mutable label. Two unrelated repos that happen to share a package name
do not collide. --dry-run reports the resolved key without writing the
file.
What it sends
- Reads
package.json(→ product name/version) andpackage-lock.json(lockfile v2/v3packagesgraph; v1dependenciesfallback) and builds a CycloneDX 1.6 JSON document withpkg:npm/<name>@<version>purls (scoped names encoded per the purl spec). POST {API_URL}/v1/sca/analyzewithAuthorization: Bearer <key>and body{ "format": "cyclonedx", "sbom": { … }, "product": { "project_key": "…" } }.- The server resolves & enriches vulnerabilities (OSV.dev + NVD + KEV + exploit/PoC signals) and persists the product, SBOM snapshot, and report to your private instance. Prints product id + component / vulnerable / new-CVE counts.
Nothing but the generated SBOM JSON is transmitted. The API key is stored
locally with 0600 permissions and is never written into your project tree.
Use in CI
# .github/workflows/sca.yml
name: SBOM SCA
on: [push]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npx @peachstudio/synapse-sbom scan
env:
SYNAPSE_API_KEY: ${{ secrets.SYNAPSE_API_KEY }}Commit .synapse-sbom.json so every CI run reports as the same product. The
exit code is 0 on success, 1 on any error (auth, network, malformed
project, API error) — fail the build on it as you see fit.
Troubleshooting
| Symptom | Cause / fix |
|---|---|
| no package-lock.json … run "npm install" first | The scanner reads the lockfile, not node_modules. Run npm install/npm ci first. |
| no API key — run "synapse-sbom login" … | No key resolved. login, or pass --key / SYNAPSE_API_KEY. |
| API 401 | Key invalid/revoked, or wrong --url (prod key against local, etc.). Check synapse-sbom whoami. |
| API 403 | Your API-key tier doesn't include SCA (Business/Enterprise). |
| API 413 | SBOM exceeds the server component cap — see the SCA API limits. |
| timed out after …s | Very large project still resolving. Re-run later (results cache) or raise SYNAPSE_TIMEOUT_MS. |
Roadmap
synapse-sbom is the first of a family. PyPI (pip) and Go scanners
will follow the same contract — generate a CycloneDX 1.6 SBOM locally, submit
to /v1/sca/analyze. The SCA engine is already ecosystem-agnostic (npm /
PyPI / Go via purl), so a CycloneDX file from any tool works today.
