Upload a software bill of materials
Push an inventory of what an agent, container image or platform is made of. Bairav matches the components against advisories and raises vulnerability findings under Security, Assets.
Supported documents
CycloneDX 1.4 to 1.6 JSON, SPDX 2.3 JSON, requirements.txt and package-lock.json (v2 and v3). The body is the raw document. Gzip is accepted with Content-Encoding: gzip.
What you need
- An ingest token bound to a telemetry source of kind
imported,sensororinfrastructure. A token bound to any other kind gets403 token_not_allowed. See Security events.
Upload from CI
samples/ingest/sbom_upload.sh
#!/usr/bin/env bash
# Upload a CycloneDX software bill of materials for one container image from CI.
# export BAIRAV_HOST=your-tenant.example.com
# export BAIRAV_INGEST_TOKEN=obt_xxxxxxxx.xxxxxxxx # must be bound to an imported, sensor or infrastructure source
set -euo pipefail
: "${BAIRAV_HOST:?Set BAIRAV_HOST}"
: "${BAIRAV_INGEST_TOKEN:?Set BAIRAV_INGEST_TOKEN}"
SBOM_FILE="${1:-sbom.cdx.json}"
# The body is the raw document. subject_key is a stable name you choose; the same snapshot sent twice is deduplicated.
curl --fail-with-body --silent --show-error \
-X POST "https://${BAIRAV_HOST}/api/ingest/sbom?subject_type=container_image&subject_key=registry.example.com/support-bot&source=ci&filename=$(basename "$SBOM_FILE")" \
-H "X-Ingest-Token: ${BAIRAV_INGEST_TOKEN}" \
-H "Content-Type: application/json" \
-H "Content-Encoding: gzip" \
--data-binary @<(gzip -c "$SBOM_FILE")
echo
Query parameters:
| Parameter | Meaning |
|---|---|
subject_type (required) | agent, container_image, dependency_set or platform |
subject_id | The agent or asset ID, when it already exists |
subject_key | A stable key you choose, for example an image name. Use it when you have no subject_id. |
subject_name | A display name |
source | ci, sensor or self_inventory. Default self_inventory for platform, otherwise ci. |
filename | The original file name |
Behaviour
- Idempotent. The same snapshot for the same subject (same SHA-256) answers
200with"deduplicated": trueand changes nothing. Retrying is safe. - Limits. 20 MB (compressed and decompressed) and 30 documents a minute per token.
- Errors carry a stable code in
detail.code, not only a message:
| Status | detail.code | Meaning |
|---|---|---|
401 | Token missing, malformed or revoked | |
403 | token_not_allowed | The token's source kind may not push inventories |
404 | subject_not_found | subject_id does not exist in your tenant |
413 | too_large | Over 20 MB |
422 | invalid_subject and parse codes | The document or subject is invalid |
429 | rate_limited | Wait Retry-After seconds |
503 | rate_limiter_unavailable, temporarily_unavailable | Retry after Retry-After; safe because the store is idempotent |
Rate-limiting fails closed: with the limiter down you get 503, never unlimited traffic.