# Changelog All notable changes to agent-bom are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow [Semantic Versioning](https://semver.org/). --- ## [Unreleased] ### Upgrade notes - Parquet and Iceberg exports move to schema version 6, which appends `malicious_basis` after `sla_due_at_source`. 0.114.0 wrote that column at position 11 under version-5 metadata, which moved every later column; consumers that read 0.114.0 files by position should re-read them by name. Iceberg tables keep their field IDs and gain the column at the end. - Ollama model agents are named with the full `name:tag` (`ollama-model-llama3:8b` instead of `ollama-model-llama3`), so two tags of one model on one host are two assets. Their asset identities change once. ### Added - `--serving-endpoint RUNTIME=URL` (repeatable) reads one vLLM, Text Generation Inference, Triton, llama.cpp or LM Studio endpoint with that runtime's documented read-only request. Each endpoint reports success, partial, denied, timeout or unavailable; only success and partial produce records, and a failed endpoint never falls back to local files. Each model records runtime, endpoint, artifact and collection evidence separately in `metadata.serving_evidence`. See [AI infrastructure scanning](docs/AI_INFRASTRUCTURE_SCANNING.md). - Deployment support tiers list, for each profile, what was validated locally and what has not been installed live. See the [deployment overview](site-docs/deployment/overview.md). ### Changed - Standalone HTML reports put only the first page of vulnerabilities, policy findings, impact rows and remediation items in the page. The other records stay in the file as inert text, and the paginator loads them a page at a time. Search, filters, sorting and counts still cover every record, and printing loads them all. Without JavaScript, a notice says how many records are stored but not shown. A 2,000-finding report opens with about 16,000 page elements instead of 220,000 (#6128). ### Fixed - An Ollama endpoint that answers 401, 403 or times out reads as denied or timed out, not unavailable, and one malformed model entry no longer discards the rest of the inventory; the result is marked partial. - `GET /v1/graph` no longer returns `503 current_estate_building` on every request when all the evidence behind the current graph is older than `AGENT_BOM_GRAPH_RETENTION_DAYS`. Age retention was deleting the rebuildable current-estate view as soon as it was built. That view is now exempt from age retention and keeps its evidence time as `created_at` (#6228). ## [0.114.0] - 2026-11-08 ### Highlights - Every finding has a scan-driven lifecycle that outlasts scan retention: status, first and last seen, resolved and reopened dates, a `resolution_reason`, and a `stale` label for open findings not seen recently. - AI triage is measured against a labelled dataset and appears beside each finding as labelled advice that never changes scanner severity; "Explain this path" writes each sentence from recorded graph edges. - Container scan accuracy: end-of-life Debian releases read `partial` until local tracker data is loaded, multi-page OSV results are followed, kernel header packages are not matched against kernel advisories, and Go binaries and their standard library are looked up. ### Upgrade notes - An MCP server with OAuth (`AGENT_BOM_MCP_OAUTH_*`) refuses to start until `AGENT_BOM_MCP_TENANT_ID`, `AGENT_BOM_MCP_OAUTH_INTROSPECTION_URL`, `AGENT_BOM_MCP_OAUTH_INTROSPECTION_CLIENT_ID` and the introspection client secret are set, and it rejects tokens without a signed `tenant_id` claim equal to that tenant. Configure the issuer first; see [MCP_OAUTH.md](docs/MCP_OAUTH.md#self-hosted-keycloak-setup). - Enabling `controlPlane.ingress` in Helm requires `controlPlane.api.trustedProxy` (or `sharedSourceAccepted`); rendering fails without it. - The `sqlite-pilot` and `synthetic-enterprise-story` Helm profiles require `AGENT_BOM_API_KEYS` in the `agent-bom-control-plane` Secret. - The Helm teardown hook's Role grants `deletecollection`, drops `get` and `list`, and holds `delete` on Secrets only for the names it removes. - Compose secret files are mode 0640 with your primary group and are read through `group_add`. Set `AGENT_BOM_SECRETS_GID` for a direct `docker compose up`. - The compose files no longer set fixed `container_name` values. Scripts that address containers by the old names should use `docker compose` service names. - Scans of end-of-life Debian releases read `partial` until `agent-bom db update --source debian` loads the Debian Security Tracker data. - `/health` adds `sso_provider` (`okta`, `entra`, `google`, `generic` or null). - Apply Postgres migrations through `20261106_01`. `20261104_01` and `20261105_01` backfill existing rows in bounded batches; `20261105_03` cannot be downgraded. See [0.114.0 upgrade guidance](docs/UPGRADING.md) for disk headroom, duration and rollback. ### Added - Helm `controlPlane.logging.json` (default `false`) and `AGENT_BOM_LOG_JSON` in the fullstack, platform and pilot compose files (default `0`) switch the API and worker pods to JSON logs. - AI triage is measured: a labelled dataset and `scripts/ai_triage_eval.py` score false-positive precision and recall, severe dismissals, calibration, invalid responses, injection resistance, latency and tokens per model, and CI replays recorded responses so a regression fails. Results are in `docs/AI_ENRICHMENT.md`. - AI advice now appears with its finding: `ai_assessment` on `GET /v1/findings`, the findings page and drawer, CLI output, CSV, SARIF and HTML, stored per scan and tenant on every store. It is labelled as advice and never changes scanner severity. `GET /v1/ai/status` says when it is off or failed. - "Explain this path" (`POST /v1/graph/explain`): on demand. The model selects recorded edges and nodes and the server writes each sentence from the record, so direction and reachability come from the graph. Evidence limits such as non-traversable hops are stated. - Each AI call is recorded with hashes rather than prompt text: in the audit chain on the control plane, with `agent_bom_ai_calls_total` and latency metrics, and in a local chained log on the CLI (`AGENT_BOM_AI_LOCAL_AUDIT=0` opts out). On the control plane, output whose audit record cannot be written is discarded. - Finding dates now outlast scan retention: `first_seen`, `last_seen`, resolved and reopened dates live in their own per-finding table, written in the same transaction as the scan. A resolved finding stays listed after its scans expire, and late, repeated or concurrent scans cannot move a finding's state incorrectly. The cleanup tick seeds existing dates from retained scans after upgrade, outside any read. Reads no longer rebuild findings for every retained scan. - Every resolved finding states why: `resolution_reason` is `no_longer_detected` or `asset_deleted`. `asset_deleted` needs a complete AWS inventory covering the asset's account, region and service, with no warnings or missing permissions, from the same source and scope. Other sources never produce it; see `docs/FINDING_LIFECYCLE.md`. - `stale` marks an open finding not observed within `AGENT_BOM_FINDING_STALE_DAYS` (default 30). It stays open and counted, can be filtered with `status=stale` on the API, `--status stale` on the CLI and the Status filter on the Findings page, and never resolves anything. - `docs/PLUGIN_SUBMISSION.md` and `make plugin-submission-check`, which stops a directory submission that would ship stale pins or draft legal pages. It stays red until the next release. - Review cases for each plugin directory in `docs/PLUGIN_REVIEW_CASES.md`, with machine-readable copies, and negative eval cases for over-triggering, chat history requests and live server launches. ### Fixed - Shared request rate limits on Postgres no longer queue in the database during a large ingest. A hit made three or four round trips, each waiting for CPU-bound ingest and graph threads to release the interpreter, and held its row locks across those waits, so other hits on the same bucket waited in the database (25 statements waited 0.4 to 0.8 s in a measured run; none after). A hit is now one pipelined round trip on a small admission pool shared with authentication state (at most four connections per process), takes no lock another hit waits on, carries 400 ms database bounds, and a request waits up to two seconds. A store outage still falls back to process-local limits. Under sustained CPU-bound load in the API process the fallback can still occur, because the request itself waits for the interpreter. - Authentication state queries on Postgres bind every value as a parameter and pipeline their transaction, 400 ms bounds and query in one round trip, instead of sending several statements as one string. - Wrong keys no longer get 503 instead of 401 when several arrive at once on SQLite. Failure writers competed for the authentication sidecar through SQLite's busy handler, which polls with growing sleeps, so a writer could lose until its 400 ms bound even when the total work fit inside it. Writers in a process now queue on one lock for the same bound. - Graph and findings reads stay fast on large estates. Effective-reach scoring walked every graph edge once per vulnerability, server and advisory row; on a 5,000-agent estate that background work held the CPU for minutes after each ingest, so the first `/v1/graph` read took 99 s and later reads were refused with 429. It now walks the edges once, with identical scores. Graph snapshot statistics (node, edge and relationship counts) are computed once per committed snapshot revision instead of on every page, on SQLite and Postgres. Measured locally at 5,000 agents: graph read p95 fell from 99 s to 2.2 s (first read after ingest 99 s to 21 s) and findings reads from 2.0 s to 32 ms; responses are unchanged. - Dashboard text and form fields now meet WCAG AA contrast in both themes. Page lane labels and scope chips used fixed dark-theme colours, so in light mode "Posture" read at 2.34:1 and "Governance" at 2.35:1; they now use theme tokens and read at 4.5:1 or better. Filled actions use the accent text token instead of white (3.65:1 before on the Security graph), the focused "Skip to content" link reads at 9.8:1 in dark mode instead of 1.92:1, and status chips use the status tokens. Form fields now draw their border with `--border-strong` (about 1.4:1 before, 3:1 or better now). Light `--status-success`, `--status-warn` and `--border-strong` and dark `--status-danger` were adjusted so each clears its threshold on every surface, and a test checks these token pairs in both themes. - Valid API keys no longer get 503 "Authentication protection unavailable" while a large ingest or graph read runs on Postgres. That work keeps the API's own threads busy, and each of the six round trips in an admission check had to wait for them, so checks missed their 500 ms deadline. Authentication and rate-limit state now share their own pool of at most four connections per process, a check is one round trip with the same 400 ms database bounds, and a caller waits up to two seconds for local scheduling. A store error or an outage still fails closed. In a 5,000-agent ingest on Postgres, 4 of 1,490 valid-key checks got 503 before and none after. - A scan of an end-of-life Debian release without local Debian Security Tracker data no longer reports `complete`. After end of life, OSV's per-CVE Debian records stop listing the release and a live query returns only DSA/DLA advisories, so fixes shipped without one were missed. The scan is now `partial` with a `vulnerability_coverage_gap` that names `agent-bom db update --source debian`. On `nginx:1.21.6` (Debian 11) from a clean install: 195 fixed CVEs in 53 packages, outcome `partial`; after `db update --source debian`: 320 fixed CVEs in 63 packages, outcome `complete`. - OSV results that span several pages are now fetched. A query with more than about 1,000 advisories returns a `next_page_token`; the scan treated it as an invalid response and marked every package in the batch as failed. Each paginated query now follows its token within firm bounds of 10 extra pages and 60 seconds per batch. A package cut off by either bound keeps the advisories read so far, is not cached, and gets an `osv_result_page_limit` coverage gap naming it, so the scan is `partial`. - Kernel header and UAPI packages (`linux-libc-dev`, `linux-headers-*`, RPM `kernel-headers` and `kernel-devel`, Alpine `linux-headers`) are no longer matched against kernel advisories. A container runs on the host kernel, so those CVEs are not exposure for the image and buried its real findings. The packages stay in the inventory and one scan note per scan gives their count and the reason; real kernel packages (`linux-image-*`, `kernel`) are still matched. `redis:7.0.11` from a clean install: 8,161 CVEs, 198 s and 722 MB peak memory before; 290 CVEs, 23 s and 229 MB after, with outcome `complete`. - Go modules found in container image binaries are now looked up. They were tagged ecosystem `golang`, which the OSV query skipped as unknown; they are now `go`, like every other Go source. The Go release that built the binary is read from its build information (Go 1.18 and later) and scanned as the `stdlib` package, so standard-library CVEs are reported. - Skill and instruction-file package extraction stops at shell operators. `&&`, `||`, `;`, `|`, `&`, redirects such as `> out.txt` and `2>&1`, command substitutions and environment assignments no longer become packages, so the skill audit no longer reports "Unknown package: '&&'", and `pip install foo; echo done` reports `foo` rather than `echo`. - Install commands in skill and instruction files are now parsed per command. Options that take a value consume it, so `pip install -r requirements.txt` no longer reports a package named `requirements.txt` or an "Unknown package" finding; the file is listed under the new per-file `manifest_references` in `skills scan` JSON. Every install on a line is read (`pip install a || pip install b` reports both). `npm i`/`add`, `yarn add`, `pnpm add`, `uv add`, `uv pip install` and `pipx install` are recognised, with scoped npm names and `name@version`; local paths, git and URL specs are not packages. Jupyter `%pip install` lines use the same parser, so a flag no longer swallows the next package and packages whose names start with `http` (`httpx`) are no longer dropped. - `agent-bom image --help` and the image docs now describe where an image is read from. In `auto` mode a reference with no registry host (`nginx:latest`) that the local Docker daemon already holds is scanned from the daemon, so it never resolves to a same-named Docker Hub image; the help previously said the daemon was used only with `--pull-mode daemon` or after a failed registry pull. The `linux/amd64` default applies to registry pulls; without `--platform` the daemon path scans the daemon's stored copy, usually the host's architecture. - Placeholder examples in Python docstrings are no longer reported as secrets: a connection string whose password is a plain word or whose host is a reserved documentation name (`user:pass@cluster.example.com`), or an assignment whose value is a plain word or phrase (`SECRET_KEY = 'development key'`). The same values in executable code, and values with digits, mixed case or symbols inside a docstring, still report. - Personal data found in translation catalogs (files under `i18n/`, `locale/`, `locales/`, `l10n/`, `lang/` or `translations/`) is reported at `low` with a `downgrade_reason`, since those strings are usually UI text or sample values. - A fresh-install scan of a Debian image no longer reports every distro advisory as `unknown`. An unrated `DSA-`/`DLA-` advisory now takes the strongest rating among the CVEs it links, looked up from `api.osv.dev` in bounded, cached batches. On `nginx:1.21.6`, unknown advisories fell from 81 of 81 to 7 of 81; the other 7 link no CVE. Offline, or when a lookup fails, the finding stays `unknown`, the scan says so and no grade is given. - `severity_source`, `severity_linked_cve` and `severity_note` state which CVE supplied a severity and why one is partial or absent, in JSON, SARIF, CycloneDX, the API, the CLI and the Findings drawer. `severity_basis` gains the value `linked_cve`. A linked score does not count when the Debian tracker marks that CVE fixed or not affected for the package and release. - Collapsing a Debian rollup into its CVE records no longer drops the rollup's severity, CVSS score or KEV status. - The README, PyPI page, first-run guide and docs quick start no longer pass `--no-discover`, which silently turned off the project's secret, personal-data, skill, dataset and training-pipeline scanning. `agent-bom scan .` already stays inside the repository; the docs now say what it covers. - API memory sizing no longer claims a push costs about 8x its body. The chart values, sizing guide and Helm guide carry peaks measured by `scripts/qualification/performance.py`: 730 MB (SQLite) and 789 MB (Postgres) at 1,000 agents, 2.4 GB and 4.1 GB at 5,000 agents (18 MB body, 116,907 package instances), where a 2Gi pod was OOM-killed. The `2Gi` default fits about 1,000 agents per push; set at least `3Gi` on SQLite or `5Gi` on Postgres for about 5,000, or split pushes. - A result where every vulnerability finding is `unknown` now grades `N/A` instead of a letter. Mixed results state how many findings have no severity. - `agent-bom scan .` in a repository no longer prints "-1 agents". The console headline subtracted projects from an agent count that already excluded them; it now shows the report's own agent count and the projects it left out. - Hints that said "use --verbose" now name a flag the running command accepts. `image`, `fs`, `iac`, `sbom` and `cloud snowflake|databricks|huggingface|ollama|posture` gain `--verbose`/`-v`, passed through to the scan. Commands without it are pointed at `AGENT_BOM_LOG_LEVEL=DEBUG`, which also prints the traceback for an unexpected error. - Under `--log-json` (or `AGENT_BOM_LOG_JSON=1`), `agent-bom api` and `agent-bom serve` write only JSON lines, including the startup summary, startup notices, Uvicorn server messages and the access log, in single and multi-worker mode. The access log carries method, path without its query, and status as fields. `AGENT_BOM_LOG_JSON` was ignored by every command with a `--log-json` flag; it is now honoured. - A healthy single-process local start no longer warns about the per-process rate-limit key or audit HMAC key; both are logged at info. They still warn in production or clustered mode, and the audit key still warns when a durable audit store is configured. - The compose files no longer pin `container_name`, so a second copy of a stack can run under another project name; services already reach each other by service name. Host ports still need to differ. ### Changed - **Behaviour change:** `skills scan` exits 2 and reports `scan_failed` when it could not scan a file, rather than exiting 0. - **Behaviour change:** skill audit context rules are stricter: more skill files that previously read as documentation now report at full severity. - **Behaviour change:** only a presented credential that failed verification now counts toward authentication backoff, marked by the handler that verified it. An expired session, a missing credential, a logged-out `/v1/auth/me` and a valid key missing a report token no longer lock out a source. - **Behaviour change:** enabling `controlPlane.ingress` in Helm now fails rendering unless `controlPlane.api.trustedProxy` declares the proxy, or `sharedSourceAccepted` records that all clients share one authentication failure budget. The hosted Compose overlay sets the trusted proxy settings, and the API warns once when a peer is outside the configured networks, when only `X-Real-IP` arrives, and on a unix socket. - **Behaviour change:** Compose secret files are now mode 0640 with your primary group, read by services through `group_add`, so `make platform-up` works on Linux without world-readable secrets. For a direct `docker compose up`, set `AGENT_BOM_SECRETS_GID`. - **Behaviour change:** audit integrity over its entry budget now reports `verified: null`, `status: not_verified_over_budget`, `total_entries` and `verification_limit`, in the API, the export and the dashboard, instead of zero verified. - **Behaviour change:** `/`, `/version`, `/docs`, `/redoc` and `/openapi.json` no longer depend on authentication state, so a source's backoff or an auth-store outage does not refuse them. See `docs/RUNTIME_FAIL_MODES.md`. - **Behaviour change:** a typosquat or dependency-confusion match now reads as suspected, not as malware. `check` and MCP report `suspected_malicious` in `verdict`, `canonical_verdict` and `status`, and say what the flag rests on and how to confirm it. It still exits `1` and `is_malicious` stays `true`. A new `malicious_basis` field (`known_malicious`, `name_similarity`, `dependency_confusion`, `unspecified`) appears in check results, reports, SARIF, CycloneDX, SPDX, CSV and Parquet. Findings, remediation text, alerts and the console use the same wording. A script that matches only `verdict == "malicious"` should also match `suspected_malicious`. - `agent-bom fs` on a directory with no packages or evaluated IaC no longer grades `A`: `posture_grade` is `N/A`, `scan_run.outcome` is `partial` and a `nothing_to_scan` issue names the directory. It still exits `0`. Any scan carrier with no packages, such as an image or SBOM, also grades `N/A`. - `agent-bom fs ` auto-detects IaC in that directory rather than in the working directory. - **Behaviour change:** an API scan whose every requested target failed, such as an unreachable image, now ends as job `status: failed` with `error` set and `result.status: failed`, instead of `done` and `no_agents_found`. - **Behaviour change:** NVIDIA CSAF bulletins apply to a PyPI package only when a CVE's own product identifies that package, and the fix comes from that product's entry. `torch`, `torchvision`, `jax`, `tritonclient`, `openai` and other packages that bundle or call a product no longer receive these findings, and `Upgrade torch to 26.07` no longer appears. - **Behaviour change:** `agent-bom mcp audit` and every scan now report what a configured launch recipe says: `remote_code_launcher` for a launcher that fetches and runs code, `plaintext_secret` for a literal secret in `env`, and `unscoped_filesystem` for a filesystem server rooted at the host root. Each is high or critical, so the audit exits 1. Blocked servers are included, and commands are read, never run. See `docs/MCP_AUDIT.md`. - **Behaviour change:** notebooks and CI workflows are no longer counted as agents or MCP servers. They have their own `notebook` and `ci-workflow` surfaces. A repository with no MCP configuration and no agent code reports 0 agents and 0 MCP servers, draws as a repository in the graph, and raises no agent-reaches-credential findings. Packages and CVEs are unchanged; findings on those packages now carry source `SBOM` and a package asset instead of `MCP_SCAN` and an MCP server asset. Saved reports keep the counts they were written with. - **Behaviour change:** secret scanning no longer reports an assignment from a function call, variable or environment lookup as a hardcoded secret, or translated UI labels as passwords. Personal-data patterns no longer match inside URLs or asset paths. - **Behaviour change:** an AI dismissal is held as `needs_review` when the recorded fix is on a different release line from the installed version. On the recorded held-out set, `qwen2.5:3b` goes from 8 wrong dismissals to 3 and from 79% to 64% recall. - AI triage warns when a model missed the published quality bar or was never measured: in the CLI summary, the JSON report, `GET /v1/ai/status` and the AI status line. - The Go SDK and example now declare `go 1.26.10`; 1.22 no longer receives security fixes. - **Behaviour change:** AI never dismisses or downgrades a KEV, malicious-package or reachable-critical finding, and a finding whose text addresses the reader goes to a person. - **Behaviour change:** providers off the loopback interface need `AGENT_BOM_AI_ALLOW_REMOTE=1`, and control-plane AI needs `AGENT_BOM_AI_CONTROL_PLANE_ENABLED=1`. A scan request's `ai_enrich` no longer turns it on by itself. - AI triage picks the riskiest findings rather than the first ones, sends the fields that decide a false positive, and reports what it skipped and why. - The investigation graph opens on what explains the first frame. A full map reads as rows of chains, draws the connections between neighbours, and holds back long ones until a node is hovered or selected. A strip above the canvas states how many connections are drawn, each card shows how many of its own are not, and Show all or Fit all draws the rest. - A connection no longer leaves the map to go around it. An exterior route more than twice the direct distance now takes the direct line, which removes the stray lines that crossed the whole frame. - On a phone, graph and paths content starts in the first third of the screen. The newer-snapshot notice fits one line, Paths, Graph, Flow and Graph options share one row, and counts and preview actions sit under the content. Paths open on the worst-rated chain. - The estate map opens on the highest recorded risks, named in a list and on the canvas, with one Investigate action. The overview's draw budget always includes them, its controls fit one toolbar, and its partial-view count now matches the map's. - The WebGL map follows its own container's size, so opening the inspector no longer leaves the canvas misaligned. - The MCP `scan` tool now reports `readOnlyHint: false`, because it keeps a redacted result locally and can refresh the advisory database. Its description says so. Tools that open no socket now report `openWorldHint: false`. - The Claude plugin's MCP servers start with `GITHUB_TOKEN`, `GH_TOKEN` and `NVD_API_KEY` blanked, so a token in the environment is not sent. Lookups use the anonymous rate limits there. - The `inventory` skill no longer has the `scan` tool, so it cannot reach the network. - The skills-only OpenAI package now declares `requires_local_executor`, since its skills run a local CLI. - The same package version in two projects is now two findings with separate dates and resolutions. Finding ids change for scans with a project: a push's `target_scope` or an API scan's target fields. Findings with no project keep their ids. Exceptions and triage assignees still apply by vulnerability and package, and ticket links are copied to each project's finding after upgrade. - An open finding stays in the default findings view after the default read window passes it; an explicit `window_days` still narrows it. - A report time more than a day ahead of when it was stored counts as the stored time, so a future-dated push cannot outrank later scans. - The GitHub Action reads OSV's application-ecosystem archives by default (`vuln-db-scope: application`, about 0.3 GB instead of 2.9 GB). OS and other packages are answered by live OSV, and the JSON report, SARIF run properties, job summary and pull request comment state the scope. Set `vuln-db-scope: full` for the previous behaviour. The Action's cache key changes, so the first run after upgrading builds a new database. - A first `--auto-update-db` refresh caps NVD at 60 seconds, newest CVEs first, and reports it as partial; later refreshes resume it. `AGENT_BOM_NVD_TIME_BUDGET_SECONDS` overrides the cap. - `--auto-update-db` prints the time each source took. ### Fixed - A database restart no longer extends an authentication outage: dead pooled connections are retried, the breaker opens only after three consecutive store errors, and one success closes it. In a private Postgres restart test, valid keys went from 25.7 s of 503s to 0.4 s. - Failed-authentication receipts have their own workers and bounded queue, so a held audit lock or a failed audit write no longer refuses other callers. Dropped receipts are counted in `agent_bom_auth_receipts_dropped_total` and recorded in the audit chain. The Postgres key-presence check no longer holds the event loop while it waits on the audit table. - One stalled SQLite transaction no longer blocks authentication checks for other sources. - A burst of distinct sources now waits briefly for authentication state instead of receiving 503. An audit write error no longer leaves the SQLite file write-locked, and an unreachable identity provider no longer counts as a failed credential. - Audit integrity is now scored per entry. Entries from a key's first use onward are verified exactly, entries no held key can check are counted as unverifiable, and links and counts are checked either way. - Websocket authentication now follows the same source limit and failure counting as HTTP. - Dropped failed-authentication receipts are recorded within seconds, with their window and sources. - The session attempt limit uses every forwarded header line and the trusted-proxy settings, as the failure limit does, and a blank key no longer spends attempts. Forwarded entries written with a port are read as addresses; unreadable ones are limited apart from the proxy's own address. - `controlPlane.api.trustedProxy.fromSecret` now requires `secretName` and reads both settings from that Secret as required keys. - All `X-Forwarded-For` lines are combined before trusted hops are counted, so a second line can neither evade the failure limit nor frame another address. IPv6 sources are limited by /64. - Attempts refused for capacity still count toward the failure limit. - The stored audit signing-key identity is now a salted HMAC. Existing unsalted digests are upgraded in place. - `run_runtime_capacity_qualification.py` no longer raises once a tenant's audit chain passes the default budget. - Pushing a large estate no longer slows faster than it grows: paged graph-build reads use an index instead of sorting the whole table, and read-only passes no longer rewrite every node they read. Stored results are unchanged. - On SQLite, a valid API key no longer gets HTTP 500 while a large snapshot commits, and a failed key write can no longer leave that worker's connection failing with `database is locked` until restart. - `agent-bom quickstart --run` completes on a plain `pip install agent-bom`. `zstandard` moved from the `api` extra to the base dependencies, because stored finding and job payloads need it on the CLI path too. - `agent-bom quickstart --run` finds `agent-bom.exe` beside the interpreter on Windows when the venv is not on `PATH`. - `POST /v1/auth/saml/login` accepts the `application/x-www-form-urlencoded` form an IdP's browser posts, as the SAML HTTP-POST binding defines. The form is capped at 1 MiB and shares the browser-session attempt limit. A verified post starts an HttpOnly browser session backed by the short-lived key and redirects to `/`; the key never reaches the page. JSON callers are unchanged. RelayState stays a one-time server nonce and is never a redirect target. - Added `GET /v1/auth/saml/start`. SAML form POST binds to the browser that started the login there: RelayState, a short-lived cookie and the response's `InResponseTo` must all match that login. Unsolicited and IdP-initiated form posts are not accepted, even with `AGENT_BOM_SAML_ALLOW_IDP_INITIATED`, which applies only to the JSON route. Point an IdP app tile or bookmark at the start URL. - `helm uninstall` no longer exits 1: the teardown hook's Role grants `deletecollection`, which it always needed, and the hook no longer selects its own Job. Deleting a Job now also removes its pods. - On macOS, gateway and proxy audit state under `/var/folders` no longer fails closed with HTTP 503. `/var` is canonicalized like `/tmp`; a symlink anywhere else in the path is still refused. - **Behaviour change:** the `sqlite-pilot` and `synthetic-enterprise-story` Helm profiles crash-looped because the API refuses a non-loopback bind without authentication. They no longer ask for anonymous access: the `agent-bom-control-plane` Secret must now carry `AGENT_BOM_API_KEYS`, and the pod stops at `CreateContainerConfigError` without it. - **Behaviour change:** the teardown hook's Role drops `get` and `list`, and holds `delete` on Secrets only for the names it removes, or no Secret access when there are none. - A current-estate cache file re-created after a sweep no longer fails with `no such table: graph_snapshots` on Linux, where the new file can reuse the old inode and looked already initialized. - The current-estate cache sweep no longer deletes a file a running store is using. Previously, starting another agent-bom process on the same state directory, or building more than 8 stores in one, could remove a live projection and cause `no such table` or `disk I/O error`. Each store now holds a lock on `.lease` that clears when it exits, and the sweep and `agent-bom db prune` skip locked files. Where locks are unavailable nothing is swept. - Two callers reaching a new current-estate store at the same moment now share one instance. Before, a scan's warm-up racing a reader could build a second one with separate build tracking. - `ctransformers` and `parsing` are no longer flagged as typosquats. Both are established PyPI projects. - A scan no longer says `supply chain looks clean` when the public registry has never heard of a package. It names the package, records a `package_not_on_registry` issue, and grades `N/A` if no scanned package exists. The exit code does not change, because private packages are normal. - The `scan` skill's frontmatter is valid YAML again; an unquoted colon in its description broke parsing in the Claude and Codex plugins. - Investigation flows: a flow that cannot apply no longer sits selected with no effect. It is disabled with the reason on screen, Automatic names what is really showing, and flows now work on maps of up to 100 nodes instead of 80, including from the connection preview. - Investigation flows: the Kubernetes exposure path now continues from a pod through its ReplicaSet and Deployment to the identity and secrets recorded there, without adding or reversing any edge. - Investigation flows: a ClusterIP Service no longer starts an exposure flow or counts as exposure, and appears in context as internal. A service account whose token is not mounted stays in context with a "Token not mounted" caption instead of reading as a step. - Investigation flows: a real 20-node Kubernetes graph opens fully framed at a legible size instead of showing 4 of 20 items. Flows always draw full cards, so edges meet their glyphs, and one long label no longer changes the spacing of the map. When a graph cannot fit, the view opens on its primary path. - Investigation flows: a second Service on the same pod no longer pulls the pod into an earlier column, Collapse findings now closes a selected finding, and the findings edge no longer runs through its own group. - Investigation flows: the Internet boundary is drawn as an unproven dashed link, and clicking it opens the recorded assessment. Display-only objects are left out of evidence totals and item counts, and have accessible names. - Investigation graph: the first frame is now readable on real scans. The connection preview wraps tall columns so cards never overlap, every chip and count on a card stays at 12px or larger when fitted, and a full map no flow fits opens along its most meaningful chain as "Automatic · Connections", with a note saying how much is in view. Edges pass behind captions, and a phone reaches graph content on its first screen. - The camera no longer stays unsettled after an animated fit is interrupted, which could leave a view waiting indefinitely. - The flow choice is kept in the URL, Reset view returns it to Automatic, and a flow's camera no longer replaces the saved camera for Automatic. - Kubernetes inventory: an EndpointSlice endpoint with no `ready` condition now counts as ready, as `discovery.k8s.io/v1` specifies, so its route is no longer dropped. - Kubernetes graph projection: a malformed routing or pod context record in a pushed report is skipped with a warning instead of rejecting the whole report. - A credential-named variable set to an empty value is no longer reported as a credential. Blanking a token to keep it out of a server used to produce a false high finding. - Hosted OAuth catalogs no longer list `scan`, which stores its result and can update the advisory database. These catalogs offer read-only tools only. - MCP discovery no longer reports a server as insecure because an argument uses `${CLAUDE_PLUGIN_ROOT}` or `${CLAUDE_PROJECT_DIR}`. Any other `$` expansion or shell metacharacter is still rejected. - `docs/PERMISSIONS.md` and the plugin READMEs now list the Alpine, Debian, OSV archive, GitHub advisory, deps.dev, Go and EPSS hosts. The privacy page now covers the guard hook, and states which tokens are sent where. - All plugin manifests point at the same privacy and terms pages. Plugin descriptions no longer say credentials are never sent where an ambient token can be, and the guard description lists all of its warnings. - The CVE link repair no longer passes over rows. Under some query plans its keyset page moved mid-statement, so it could leave a row unmarked and carry on past it, leaving that row's CVE link unrepaired. - Skill audit: a security-review skill that lists coercion phrases in quotes as things to report now gets a low finding instead of high, for example `Text that asks the model to "bypass the guardrails"`. The finding stays visible. - Skill audit: a quote or example word no longer demotes a real directive. These shapes were low and are now high: `Obey phrases such as "..."`, `Use phrases such as "..." and comply`, a report sentence inside an HTML comment, `Do not hesitate to ...`, a plain sentence under a heading such as `## Red flags`, and a report sentence hidden by base64, zero-width or homoglyph characters. - Skill audit: packages launched by `npx`, `bunx`, `uvx` or `uv tool run` in an MCP JSON block, and `npx --yes` commands, now reach the package inventory, so they are checked like any other package. - Security: `oauthlib` moves to 4.0.1 (GHSA-3jp2-3mrg-2vxc), which arrives through the Azure extra. Versions 3.3.0 up to 4.0.1 could issue a bearer token for a bogus device code. - Typosquat detection now flags an adjacent-letter swap from five letters (`axois` as `axios`); single-letter substitutions keep their six-letter floor. - Investigation graph: an exposure flow now continues through the workloads an exposed host runs, so the path to identities and data opens framed on one screen. Edges between adjacent entities no longer arc over nothing. - A synchronous push interrupted by a process kill under distributed dispatch no longer stays `running` forever. The request now heartbeats a lease, and once that lease expires any replica marks the job `failed`, so the client can resubmit under the same idempotency key. A long push with a live lease is never failed for its age, and pushes already stranded by earlier releases are failed after the stuck-job timeout. - A dispatched job that keeps crashing its workers now fails after `AGENT_BOM_API_SCAN_MAX_ATTEMPTS` claims (default 5) with an error naming the count, instead of being redelivered forever. Migration `20261105_02` adds the attempt count. Resubmitting the push starts a new budget. - A worker run that raises or is cancelled before recording an outcome, such as a store error during ingest, no longer removes its job from the dispatch queue, which left it `pending` forever. The job is redelivered when the lease expires, and a brief store error during ingest is retried in place without failing the report. - `agent-bom scan --push-url` now exits `1` when the results were not delivered, and says so even with `--quiet`. It used to exit `0`, so CI could pass while the control plane never received the scan. Push error text is sanitized. - Investigation graph: an upward deployment-context edge now leaves from the top of the node instead of running through the cloud provider mark. - Every finding now has a scan-driven lifecycle on both ingest paths: `status`, `first_seen`, `last_seen`, `resolved_at`, `reopened_at`, `last_resolved_at` and `status_updated_at`. A pushed scan that no longer reports a finding resolves it instead of dropping it, `status=resolved` retrieves it, and a returning finding reopens with its original `first_seen`. Partial, failed, inventory-only and differently scoped scans resolve nothing. See `docs/FINDING_LIFECYCLE.md`. - `POST /v1/findings/bulk` with `reconcile_absent` no longer resolves other assets of the same source: it covers the assets the batch names or lists in `scanned_assets`, unless `reconcile_scope: "source"` asserts a full snapshot. A complete empty batch can now resolve, a non-complete `scan_run` skips reconciliation, and an unusable `observed_at` is rejected with 422 on bulk and compliance ingest. - A reconciling bulk batch that sends its own `canonical_id` no longer resolves its own findings: the batch's present set now identifies rows the same way the store does. - The Findings page has a Status filter (Open, Resolved, All), shows resolved and reopened dates, and labels partly fixed issues such as "1 of 2 open". - A later finding on the same CVE no longer erases earlier CVE details or its KEV verdict, and every finding that names a CVE follows that CVE's KEV verdict in counts and lists alike. - CVE records merge under row locks in a fixed order, so concurrent writers keep every field and batches naming the same CVEs cannot deadlock. KEV can no longer sit in only one of a record's column and payload. - Migration `20261105_01` and the control plane's cleanup tick link existing CVE findings to their record and reconcile records that disagree on KEV. Fields a replacing writer already overwrote come back only from a rescan or a catalog sync. - KEV follows the CISA catalog on the control plane. A fresh, complete catalog already on the replica sets KEV with its added and due dates and clears entries the catalog no longer lists; a missing, stale, empty or truncated catalog changes nothing. `agent-bom db update` now removes delisted entries, and only a complete feed can remove one. - A first vulnerability database build writes about a ninth of the data it did: it builds beside the target with no write-ahead log or flushes, and only a finished file is renamed into place. A refresh of an existing database keeps its crash-safe settings and checkpoints less often, so it flushes about 20 times less. - With a scoped OSV archive, a local hit in an ecosystem outside the scope no longer stops the live OSV lookup for that package. - The `install-from-source` input now says that it only works when the workspace is a checkout of this repository. - Cloud scans show a grade with partial evidence, such as `F (partial, 54 of 56 evaluated)`, scored as pass / (pass + fail + unknown). Partial grades cap at B and under 50% coverage shows N/A with the reason, so failing and clean accounts no longer both read N/A. - Cloud checks with nothing to inspect report `not_applicable` instead of `pass` across AWS, Azure, GCP, Snowflake and Databricks. - A disabled GCP API is recorded as not in use, and a provider with evaluated controls is `partial`, not `failed`. An errored check no longer reads as a finding in the exit reason. - KEV counts and the `kev=true` filter no longer miss findings whose stored payload is compressed; existing rows are backfilled by migration `20261104_01`. - Overview, posture and grouped findings report exact issue counts from a store aggregate at any size, so totals no longer shrink as data grows and no severity reads 0 because a row budget ran out. Coverage lanes and the Vuln / SCA card are exact on the same basis. - First reads of overview, `kev=true` and posture counts no longer join the whole ledger; they read indexed columns. - Scoped reconciliation resolves findings whose source sits in a compressed payload, and a cached findings total is dropped once another replica writes. - SARIF uploads are accepted by GitHub code scanning: every result and related location has a physical location, and findings with no repository file use a marked `agent-bom-findings/` path with `properties.no_source_file` instead of a logical-only or `docker://` location. The upload action computes the line hash, so its per-result fingerprint warnings stop. Combination and prompt findings point at the MCP config and instruction file. - The GitHub Action treats an empty `severity-threshold` as report-only, as documented. A partial scan warns and reports `scan-status: partial` rather than stopping the baseline step; malicious packages, failed scans and explicit policy or KEV gates still fail it. - `--baseline --delta` and `agent-bom/v1` fingerprints no longer depend on the checkout folder name, so a docs-only pull request passes the documented gate. Older baselines still match. - The Action's job summary, annotations, pull request comment and MCP gate write UTF-8 on Windows runners instead of failing on `→`. - Container inventory probes executable headers before searching for Go build metadata, avoiding false coverage gaps for oversized data files. - Scoped npm namespace lookalikes are checked against ranked scoped targets while preserving unrelated namespaces and official package families. - Release preflight requires the exact main commit to pass every full Python correctness shard, combined coverage, UI lanes and runtime acceptance; an older green run cannot override a newer unsuccessful run. - Cloud posture grades use evaluated controls and remain unavailable when collection is incomplete. Explicit cloud scans collect selected-provider native inventory without local workstation discovery; failed inventory retains a partial receipt. - Disabled GCP APIs and billing are reported as unevaluated controls with service-state guidance, while permission and unexpected collector failures remain errors. - File-backed registries, configuration and reports use explicit UTF-8, restoring MCP startup and Unicode evidence on Windows systems with a legacy default encoding. - Container binary probes search in small chunks while retaining Go metadata beyond the first window; OCI changes always select the memory-bound regression suite in CI. - Cloud provider commands isolate collection from workstation discovery, resolve active Azure/GCP targets when explicit scope is absent, and give safe Databricks re-authentication guidance. GCP logging checks use the Logging SDK's service client modules. - Mixed Python requirements retain exact pins when resolving ranges; framework discovery no longer treats range bounds as installed versions. Independent requirements pins remain visible alongside Poetry and uv lockfiles. - Scoped npm package names are assessed within their namespace, preventing unrelated unscoped names from producing typosquatting or dependency-confusion alerts. - Failed Docker MCP image expansion retains the rest of the scan in a partial report. Container inventory includes Go binaries in application directories and distroless dpkg status fragments. - Multi-document pnpm lockfiles retain package inventory and dependency relationships from each document. - Reports retain digest-qualified image coordinates and credential variable names while continuing to redact secret values. - Unresolved range advisories produce a partial, review-required result without a posture grade; Markdown and CSV include the review candidates. - Image inventory without an evaluated agent entrypoint retains unknown dependency reachability, preserving structural CVE paths without claiming execution. - Graph path technique enrichment reuses the batch hop index instead of repeatedly reading the same adjacency lists. - Scanner and install guard agree on scoped package typo warnings: unknown namespaces retain leaf checks, lookalike scopes target known scoped packages, and legitimate scoped package names remain clean. - Keep distributed scan recovery lease-owned and publish pushed-result completion only after graph persistence. - The sign-in page shows SSO buttons to signed-out visitors. It reads the configured sign-in modes and the provider family from `/health`. - Overview no longer fails to render when a finding's `affected_servers` holds objects; ingest stores server and agent names or ids. - Text that used a removed colour token is readable again in both themes. - Graph links accept every layer the graph URL supports. ## [0.113.2] - 2026-11-03 ### Fixed - Scan pipeline nodes remain visible when stage telemetry refreshes during initialization, preserving measured geometry separately for readable and overview layouts. - Graph captions retain recorded cloud-service identities, including Amazon EKS, AWS IAM roles and Azure Blob containers. Clearer resource glyphs and provider badges distinguish mixed-vendor connections; missing or conflicting metadata keeps a generic caption. - Current-estate graph reads retain their previous complete generation while a background worker promotes new evidence, avoiding a transient unavailable response during ingestion refresh. The response labels retained evidence as the previous generation. - Hosted MCP startup preserves configured OAuth instead of forcing an incompatible public read-only tier. Railway and Procfile deployments use the authenticated default. - Release and deployment-freshness checks use the configured managed credential, verify the exact release contract, and reject anonymous MCP access. - Release checks distinguish an accepted deployment upload from a verified rollout. Failed startup, stale deployment evidence, and unavailable probe credentials cannot report a successful rollout. ### Upgrade notes - Keep the existing OAuth issuer, audience and subject configuration. Do not combine OAuth with the optional public read-only tier. - An unavailable identity provider leaves deployment verification failed; rerun verification after provider recovery. ## [0.113.1] - 2026-11-03 ### Highlights - Investigate inventory and findings on one scoped graph with readable names, circular entity icons, grouped findings, recorded relationship details, and light/dark/mobile layouts. - Apply scoped IaC exceptions and policy rules while retaining suppressed evidence in reports and an audit trail. - Discover Continue user-level YAML MCP configurations without executing configured commands. ### Added - IaC exceptions with an audit trail: `.agent-bom-ignore.yaml` entries scoped by rule, path and Kubernetes resource (kind, name, namespace, labels) with required reason, optional owner and expiry; inline markers accept `expires=` and `owner=`. Accepted findings stay in JSON (`iac_findings.suppressed`), SARIF (`suppressions`), HTML and console, and leave the gates. Expired exceptions re-activate their findings with a warning; exceptions due within 14 days print a notice. A malformed IaC entry in the ignore file stops every scan up front, with or without IaC paths. - Tenant IaC exceptions through `POST /v1/exceptions` (`iac_rule_id`, `iac_path`, `iac_resource`) with the existing four-eyes approval, bounded expiry and tenant scoping; repository scans through the API and project scans by the MCP `scan` tool apply them, and MCP scan results now include the project's IaC findings. - Policy-as-code rules for IaC findings (`iac_rule`, `severity_gte`, `iac_path`, resource, labels, `iac_environment`) with `allow`, `warn` and `block` actions; a non-waivable `block` rejects repository-local exceptions. `agent-bom iac` accepts `--ignore-file` and `--policy`. ### Changed - Dashboard navigation exposes every platform group without Personal, Shared or Governance presets. Retired browser preferences no longer hide reporting or source setup. Deployment settings and permission checks remain authoritative. - Executive briefs emphasize issue groups, severity, remediation ownership and evidence coverage; source and signing details expand on demand. A finding no longer detected by a comparable scan is not labelled a verified remediation. ### Fixed - Dense graph snapshots open with a labeled connection preview and circular nodes; the full loaded map and every starting point remain available. Phone previews reserve enough scrollable canvas space to keep both endpoints visible. - Graph entry pages defer closed evidence inspectors until opened, reducing initial JavaScript loading while preserving the first-useful-paint budget. - SQLite graph writes build the search index from bounded node batches, avoiding a second full-node read during cold current-estate projection. Search content and atomic replacement remain unchanged. - Findings retain source, occurrence and partial-evidence context across API results and graph investigations; incomplete collection is not presented as a clean result. - Push ingestion avoids blocking the API event loop, retains idempotency boundaries and isolates background graph enrichment from mutable report objects. - Scheduled scans revalidate leadership and the current tenant-owned schedule before dispatch; deleted, disabled or rescheduled stale entries are skipped. - Continue's `~/.continue/config.yaml` is discovered on macOS, Linux and Windows. Malformed YAML does not hide legacy JSON configurations, and discovery does not execute commands (#6147). ### Upgrade notes - Postgres migration `20261102_01` adds IaC exception scope columns. Migration `20261102_10` adds missing fleet endpoint storage and retry-safe trend scan identity to upgraded databases; both are additive and idempotent. - Retired dashboard product-view preferences no longer hide navigation. Permissions and evidence scope remain authoritative. - See [upgrade guidance](docs/UPGRADING.md) for backup, migration and rollback verification. Scheduler revalidation does not guarantee exactly-once execution across crashes or leadership loss after the final check. ## [0.113.0] - 2026-11-01 ### Highlights - Azure and GCP Terraform coverage: 23 new rules (`TF-SEC-101`..`112` for `azurerm_*`, `TF-SEC-201`..`211` for `google_*`) with NIST tags, remediation, ATT&CK mappings and CIS Azure/GCP control ids (all but `TF-SEC-110`, which awaits a pinned benchmark version). - Taint flow findings carry severity and CWE on every surface (code JSON, unified findings, console, both SARIF exporters), so they rank and export alongside other findings. - MCP audit detects hidden-instruction tool-description poisoning, and the session's own scan result now answers `blast_radius`, `should_i_deploy` and `exposure_paths`. - Bounded local storage: current-estate projection caches and the local analytics mirror are swept automatically, and the new `agent-bom db prune` previews or removes stale projection caches. ### Upgrade notes - See [0.113.0 upgrade guidance](docs/UPGRADING.md) for compressed pushes, retention defaults and count changes. - CLI pushes are gzip-compressed by default. A control plane older than 2026-09-10 (before gzip push decoding, #5193) rejects compressed pushes; set `AGENT_BOM_PUSH_GZIP=0` on collectors that still push to one. - A Postgres URL in `AGENT_BOM_DB` (`postgresql://...` or `postgres://...`) is accepted at boot as the alias of `AGENT_BOM_POSTGRES_URL`. SQLite store openers still refuse it, with a message naming both variables. - The decoded push budget (`AGENT_BOM_API_RESULT_PUSH_MAX_BYTES`) defaults to 256 MiB; gzip push bodies that expand beyond 100:1 are refused with 413. - The local scan mirror now drops whole runs older than 90 days or past 2 GiB of live data, always keeping the newest run. Raise or disable (`<= 0`) `AGENT_BOM_ANALYTICS_MAX_RUN_AGE_DAYS` / `AGENT_BOM_ANALYTICS_MAX_BYTES` before upgrading if the local mirror holds history you need. Compact an existing oversized mirror once with `agent-bom report prune --apply --compact`. - New environment variables: `AGENT_BOM_EXEC_PREWARM` (default on), `AGENT_BOM_CURRENT_ESTATE_CACHE_MAX_AGE_DAYS` (default 14), `AGENT_BOM_ANALYTICS_MAX_RUN_AGE_DAYS` (default 90) and `AGENT_BOM_ANALYTICS_MAX_BYTES` (default 2 GiB). See [ENV_VARS](docs/operations/ENV_VARS.md). - npm lockfile scans no longer report workspace members or their `node_modules` symlinks as packages, and model binaries are scanned by default; package and finding counts can change between 0.112.1 and 0.113.0 scans of the same project. - The weekly MCP Registry Sync needs "Allow GitHub Actions to create and approve pull requests" (Settings, Actions, General) to open its PR; without it the run opens or updates one tracking issue and fails with that reason. ### Added - Azure Terraform rules for public storage, internet-open NSG rules on SSH/RDP/all ports, database public access and TLS, Key Vault purge protection, disk CMK encryption, VM public IPs, flow logs and SQL auditing/TDE; GCP rules for public buckets, open firewall rules, Cloud SQL public IP/SSL/backups, OS Login, serial console, subnet flow logs and IP forwarding. A depth-aware HCL helper keeps nested flags from being read as resource flags, and AWS rules no longer fire on Azure/GCP files or vice versa (#6145). - Taint flows map to CWE-89 (SQL), CWE-78 (command), CWE-502 (deserialization), CWE-95 (eval), CWE-918 (SSRF), CWE-79 (XSS), CWE-22 (path) and CWE-1427 plus OWASP LLM01 (tainted LLM prompt); prompt-injection flows are promoted to high findings and SARIF rules carry `security-severity` and CWE tags (#6145). - Continue project configs (`.continue/config.json`, `config.yaml`, `mcpServers/` blocks, legacy `experimental.modelContextProtocolServers`) are discovered, and the Vercel AI SDK is detected from its real packages (`ai`, `@ai-sdk/*`) (#6145). - `docs/VENDOR_COVERAGE.md` capability matrix with counts read from code, including an explicit "not provided: HTTP/API dynamic testing" row (#6145). - `agent-bom db prune` previews stale current-estate projection caches and deletes them only with `--yes`; `report storage` shows free pages so an oversized mirror is visible (#6144). - The executive brief (`GET /v1/brief`, MCP `executive_brief`) carries `sla_status` (overdue / due soon / on track) and an `sla_policy` display name next to the raw `sla_due_at`; the UI shows relative and absolute dates, an SLA chip and the policy name, including in the Markdown export (#6142). - Advisory affected-asset rows carry `asset_display` (image ref/tag or server name, kind, owning agent, host) from the graph, and the summary names its `count_basis` (#6142). - MCP introspection and live audit detect hidden-instruction tool-description poisoning: hidden tags, "do not tell the user", credential-file paths, exfiltration URLs, tool shadowing and base64 blobs (#6143). ### Changed - Live Activity serves an anonymous no-auth session the REST gateway feed (`GET /v1/gateway/feed`, polled every 15 s) instead of a sign-in prompt; the ledger stream still requires a signed-in session, and the empty state appears only when the API returns no events (#6142). - The get-started project command pre-fills this deployment's `/v1/results/push` URL, shows the API-key step only when the session needs a key, links key-capable users to the API-key page, and offers an in-product action beside the CLI snippet (#6142). - `/compliance?framework=iso-27001` (and other API/finding slugs) resolves to the matching framework section; selecting a framework writes its slug back into the address bar (#6142). - An anonymous reader of the seeded demo estate is labelled "Demo visitor / Read-only demo" instead of "Unauthenticated access" (#6142). - The exec read cache is generation-driven with a 15-minute safety TTL, and the four exec reads (counts, compliance summary, fix-first, brief) are warmed in the background after a demo seed or a results push, so a dashboard opened after either no longer pays the rebuild (#6142). - Every demo agent records its kind, platform and a fictional host, so the hero attack path no longer reads "Agent kind not recorded · Host not recorded" (#6142). - `docs/DEPLOY_PLATFORM.md` gains the Postgres-without-Compose/Helm checklist (#6142). - npm lockfile parsing no longer emits workspace members or their `node_modules` symlinks as packages; a member's dependencies carry `parent_package=` at depth 1 instead of appearing as root packages (#6143). - One canonical tagline across `--version`, `--help`, the Docker label, Helm chart, GitHub Action, registry manifests, skills and the social preview; the release consistency check enforces it and the MCP registry description length (#6143). - README leads with why an AI supply-chain BOM matters, the standards findings map to, and a four-row offerings table (#6143). - Model binaries are scanned by default under the existing pickle size and opcode caps; the quick preset prints a `--model-files` hint instead (#6145). - `agent-iac` help and the Docker MCP registry readme state "200+" IaC rules with a pointer to the capability matrix instead of stale counts (#6145). - Current-estate projection files are swept on store construction (newest 8 kept, age cap `AGENT_BOM_CURRENT_ESTATE_CACHE_MAX_AGE_DAYS`, the active file never removed); the local analytics mirror uses incremental auto-vacuum, releases pages after prune and applies age and live-byte caps (#6144). - MCP Registry Sync uses one stable `chore/mcp-registry-sync` branch, probes whether Actions may open pull requests, and opens or updates a single tracking issue when PR creation is refused (#6144). ### Fixed - First-run scan accuracy: private npm workspace members are no longer reported as typosquats or resolved against the public registry; a local `agents/` package is no longer reported as the OpenAI Agents SDK; an unresolvable manifest records a coverage warning instead of aborting the scan with exit 0 (#6143). - JSON reports keep structural identifiers (`exposure_path_id`, `package_purl`, `server_ref`) for scoped npm packages; credential-pattern redaction still applies to every value (#6143). - Image scans record suppressed unfixed OS-package findings in the summary and never print a clean verdict over them (#6143). - MCP server: `blast_radius`, `should_i_deploy` and `exposure_paths` consult the current session's scan result before persisted evidence or host discovery (#6143). - MCP introspection accepts servers launched by a verified absolute launcher path; skipped servers are recorded with the reason (#6143). - GitHub Action summary reports the posture grade and path counts recorded in the report instead of recomputing them (#6143). - Push 413 responses say how to split the scan; the measured 10k-package report (154 MB) fits the new 256 MiB decoded budget (#6142). - Root-caused CI flakes: the 390 px graph-workspace E2E spec, a graph-builder mock leaking across tests, and a `sys.modules` eviction that left a stale cloud submodule; no retries or widened timeouts (#6144). - Intentionally outdated SBOM fixtures are excluded from repository vulnerability scoring through a directory-scoped `osv-scanner.toml` (#6144). - Browser credential binding regression coverage (#6135), closed cleanup and action result readers (#6136), failed-scan posture in console summaries (#6137), GCP unresolved-boundary evidence (#6138), graph accuracy on validated findings (#6139) and consistent NVD score normalization across sync paths (#6140). ### Security - Gzip push bodies past 1 MiB decoded that expand beyond 100:1 are refused as decompression bombs; inflation stays bounded per step and against the decoded budget (#6142). - `docs/THREAT_MODEL.md` records the 0.113.0 trust-boundary review: descriptor poisoning detection, absolute-path launchers, identifier-safe redaction, MCP session result scoping, push budgets, exec read prewarm, cache and mirror retention, and the registry-sync tracking issue. ## [0.112.1] - 2026-10-31 ### Highlights - Import customer-selected security-lake findings into the existing authenticated findings and graph workflow, retaining scope, observation times and source receipts. - Preview and export scoped executive briefs from the dashboard, CLI, API and MCP, with remediation ownership, evidence drilldowns and explicit verification boundaries. - Investigate component findings with advisory context, fixed versions, connected evidence and clearer graph navigation. ### Upgrade notes - See [0.112.1 upgrade guidance](docs/UPGRADING.md) for package extras, image roles, retained evidence and post-upgrade checks. - Supersedes the unpublished v0.112.0 tag. Artifact publication was blocked by an expired bundled ATLAS catalog. - Base CLI installations no longer include unused Flask and Tornado dependencies. API installations retain the filesystem-jail dependency through `agent-bom[api]`; the developer extra includes the API dependencies. - Use the dependency-free `sca-import` extra for external SCA report imports. The existing `snyk` extra remains a deprecated compatibility alias. - Lake ingestion accepts bounded JSON/NDJSON snapshots from local files or an explicitly version-pinned S3 object. Warehouse queries, native Parquet ingestion and continuous subscriptions are outside this workflow. ### Added - Agent context in the investigation graph separates platform association, recorded execution hosts, model links and environment membership, with bounded references and explicit missing-evidence labels. Generic provider relationships no longer claim hosting. - Dedicated Get started page, linked from a compact Overview setup card and Connect navigation, with explicit control-plane scan, source connection and local-project push paths; expandable credential-free commands, inventory-to-impact-to-verification guidance, and a separate browser-only report preview. - Project activation with retained scan/graph receipts, shared-fix prioritization, and a CVE impact workspace showing recorded workflows, advisory conditions and conditional reach without claiming local exploitability. - Dashboard executive brief with Markdown/JSON exports, finding and graph drilldowns, source-scope disclosure, and authenticated compliance-pack/key downloads with explicit verification guidance. The read-only demo retains sample labels and evidence limits. - Lake import activation in Connections, with a packaged `agent-bom ingest lake-sample` workflow, private local report artifacts, server-recorded graph persistence counts, and scan-scoped Findings and Investigation links. - `agent-bom ingest lake` maps selected finding observations into a private report and can push it to a configured control plane. Input and mapping digests, scoped identifiers and observation times support replay and provenance; source-declared controls remain evidence tags rather than attestations. - Per-agent novel-tool alerts use a bounded in-memory baseline and report previously unseen tools after baseline warmup. Alerts are advisory and do not change enforcement decisions. - Authenticated executive briefs through `agent-bom report brief`, `GET /v1/brief`, and the `executive_brief` MCP tool: canonical posture, remediation owners and SLA provenance, ranked exposure paths, technical control evidence, scoped scan history, and links to the signed compliance pack. Sample-data and incomplete-evidence boundaries remain explicit. ### Changed - Azure multi-subscription and GCP multi-project onboarding share discovered scopes between inventory and CIS collection, retain per-account attribution, and preserve partial-collection warnings. - Scanner, API/storage, graph, output and dashboard modules are split behind existing interfaces, with ratcheted file and function size checks. - One lead message on every public surface (README, docs home, PyPI and Docker Hub descriptions, package metadata, registry manifests): "AI supply-chain BOM: every agent, MCP server and AI package, and what each one can reach." The README leads with the measured real-repository accuracy, shows the `db advisory affected` / `affected_assets` commands for a new CVE, keeps five badges, and points to GitHub Discussions first. - `docs/THREAT_MODEL.md` records the gateway/posture audit outbox (leased, fenced acknowledgements) and the MCP `scan` `project_path` filesystem boundary. ### Fixed - First-run project scans retain an HTML report with responsive evidence tabs, expandable finding details and print layouts. Missing scores remain distinct from zero; stale catalog evidence is labelled explicitly. - Explicit enrichment requests remain effective under quick scan profiles. Distribution-ambiguous package matches remain possibly affected and incomplete until distribution evidence resolves them. - Ollama discovery preserves the selected endpoint and collection provenance; an unavailable configured endpoint never substitutes local manifest inventory. Missing AISVS exposure evidence remains unknown. - Current-agent counts avoid materializing graph paths; retained-report reads reduce repeated decoding, and advisory aliases use indexed lookups. - Published MCP images use verified release Git contexts and distinct API/MCP image identities. Released-image dependency refreshes update pyasn1 where installed. - Cloud inventory summaries in REST and MCP preserve incomplete enabled-provider collection instead of reporting success from enablement alone. Missing SDK states and partial Snowflake discovery remain visible without discarding successful resource counts. - Retain collected cloud assets and managed Kubernetes GPU pools from explicitly partial inventory in the graph, while preserving incomplete scan coverage and scoped reconciliation. - Release preflight and CI inspect the bundled ATLAS catalog even when a newer operator cache exists, using the same 180-day freshness limit. The bundled catalog is refreshed from the upstream source. - Affected-advisory answers include image packages and distinguish stale observations from confirmed current evidence; VEX filtering and finding totals use aligned semantics. - LangGraph topology retains `Send` fan-out edges. Secret scanning distinguishes CPython module links from password values. - Released-image refreshes patch Tornado where installed and verify collector and UI refresh completion. - Finding-backed graph assets retain recorded provider, account, region and environment. Imported rows with different observation times keep their own node and relationship timestamps through persistence instead of inheriting the oldest observation in the batch. - Component findings place recorded advisory context, relationship explanations, known fixed versions, connected neighbors, and scoped next steps in a responsive investigation view while preserving snapshot and coverage boundaries. - Findings, audit, trace, and graph drill-down links preserve the configured deployment prefix. The static demo reports explicit zeroes for empty severity buckets and directs onboarding links to installation instead of unavailable sign-in. - Release automation: the post-release pin job pushes its branch and ends as a labelled skip with the manual `gh pr create` command when the signing key or the "Allow GitHub Actions to create and approve pull requests" setting is missing; the MCP SSE deploy separates "deploy succeeded, probe deferred" (OAuth provider outage, with the token endpoint status) from a failed deploy; the release run calls the docs build alone instead of showing a skipped Pages deploy. - PR CI: the kind/Helm runtime acceptance lane runs on PRs only for chart, runtime deploy or lane changes, and Dependency Review skips the snapshot diff when no manifest, lockfile, Dockerfile, chart or workflow changed. - Small multi-source graphs use balanced relationship ranks, retain directional arrows, and reveal relationship captions on selection. - Completed graph queries keep display labels in the inspector instead of rewriting the URL, preserving newer root navigation and explicit link labels on slower browsers. - First-run console output: repeated CI-hardening warnings collapse to one line per rule with a count, IaC rule groups count occurrences instead of splitting per message, a scanned repository is counted as a project rather than an agent, the dependency legend spells out direct/transitive/unknown, a lone critical says why it is P2 rather than P1, and the compliance block appears only with `--compliance` or benchmark evidence (one hint line otherwise). - Reports written to a file (including through a saved profile that pins `format`/`output`) confirm the path on stdout instead of leaving it empty. - `agent-bom iac` no longer flags `uv pip install --no-cache` as a missing `--no-cache-dir`; the shipped `Dockerfile` pins its Alpine packages. - Secret scanning no longer reports template placeholders as hardcoded secrets. Go/Helm/Jinja `{{ ... }}` actions, `${VAR}`/`$VAR` references, printf verbs (`postgres://%v:%v@%v`), `` values and a value that only repeats its key name (`password = "password"`). The same rejection applies to Terraform `TF-SEC-051`. Findings under `testdata/`, `__fixtures__/` and `__mocks__/` are kept at `low` severity with a `downgrade_reason` instead of their default severity. ### Deprecated - `agent-bom gateway serve --oauth-as-issuer` / `AGENT_BOM_GATEWAY_OAUTH_AS_ISSUER` is hidden and ignored (the embedded OAuth AS is unavailable); it will be removed in a later release. ## [0.111.0] - 2026-10-28 ### Highlights - **"Am I affected by CVE-X?"** answered across every stored scan, from the CLI, API, MCP, UI, skills and Action, using every alias record of a vulnerability. - **More accurate dependency scans on real repositories:** Gradle variables, `setup.cfg`/`setup.py`, full requirement ranges, lockfile-owned workspaces and Maven parent POMs, measured against public Temporal and Snowflake repositories. - **Runtime protection you can switch on:** `--injection-mode enforce` removes poisoned MCP tools and blocks injected tool results; the default stays alert-only. - **A sturdier self-hosted control plane:** probes survive a database outage, operator API keys stop expiring, SQLite deployments keep their keys, and large images scan in bounded memory. - **One severity gate:** the CLI now fails on high or critical findings, the same as the GitHub Action (see Upgrade notes). ### Upgrade notes - **The CLI severity gate now defaults to `high`**, the same as the GitHub Action, so a repository no longer passes locally and fails in CI. A plain `agent-bom scan` with a high or critical finding exits `1`. Keep the old behaviour with `--fail-on-severity critical`, or make a run reporting-only with `--exit-zero`. - `agent-bom check ` without a version now checks the latest published version and reports `version_source` (`requested`, `registry_latest` or `registry_fallback`). When the latest version cannot be resolved, the result is incomplete and exits `2`; previously it was skipped with exit `0`. - `agent-bom proxy` and the gateway can now enforce, not only alert, on poisoned tool descriptions and injected tool results (`--injection-mode enforce`). The default stays alert-only in this release. - Completed scan-job results are now stored zstd-compressed in SQLite and PostgreSQL (see `docs/STORAGE_BACKENDS.md`). Existing rows are read unchanged and nothing is rewritten, but earlier releases cannot read the new rows: during a rolling upgrade, or before a downgrade, set `AGENT_BOM_JOB_RESULT_CODEC=none` on every writer. - JSON report `blast_radius` rows move to `schema_version: "2"`: the embedded `exposure_path` object, an exact copy of the matching `exposure_paths.paths` entry, is replaced by `exposure_path_rank` (1-based index into `exposure_paths.paths`) and `exposure_path_id`. Read the path with `.exposure_paths.paths[.exposure_path_rank - 1]` or `agent_bom.output.exposure_path.blast_radius_exposure_path(report, row)`, which also reads schema `"1"` rows. SARIF results still embed their path. - `--gpu-scan` reports and the MCP `gpu_infra_scan` result drop `driver_findings` and `driver_cve_count`, which were computed from fixed version floors rather than advisories. NVIDIA driver CVEs now appear as ordinary vulnerabilities on the `nvidia-gpu-display-driver` package of the `k8s-gpu-cluster` agent; the cluster scope lists `driver_versions` per vendor. - Shared gateway audit delivery (`AGENT_BOM_GATEWAY_AUDIT_BACKEND=postgres`, Helm `gateway.auditBackend`) adds Alembic revisions `20261027_01` to `20261027_03`. `20261027_02` (delivery leases) has no downgrade, and `20261027_03` adds a stored generated column to `drift_incidents` under an exclusive lock: run the migrations before starting new replicas and schedule them outside peak hours on large tables. ### Added - LangGraph topology in `scan`: `add_edge(START, …)` / `set_entry_point`, `add_edge(…, END)` / `set_finish_point`, `add_conditional_edges` and `set_conditional_entry_point` (one `delegated_to` edge per branch, carrying the branch label), `add_node(fn)` with the inferred name, subgraphs (`add_node("sub", child.compile())`, nested under their node via `parent_id`) and `Command(goto=…)` handoffs are read with `declared` provenance. The JSON report lists them per agent; in both graph views the edges keep every branch label that leads along them and an edge `kind` (`entry`, `finish` for a node returning control to its graph, `subgraph`), and unified-graph agent nodes carry `parent_id`, `unresolved_route_count` and `unresolved_route_reasons`. Graph bindings and node functions resolve by lexical scope, so builders with the same name in different functions stay separate graphs, and an aliased `StateGraph` import is recognised. Routes the parser cannot resolve (no path map, a non-literal path map or member, a computed `goto`) are listed on the source node as `unresolved_routes` and mark it `dynamic_edges` instead of being dropped; a file yields at most 256 targets per call and 5,000 edges, and a cap that is hit is recorded as a `truncated` unresolved route. Previously only `add_node("name", fn)` and string-literal `add_edge` were read, so a supervisor graph scanned as disconnected nodes. - LangGraph prebuilt multi-agent shapes: `create_supervisor` (supervisor → members, members hand back, `.compile(name=)` naming nested teams), `create_swarm` (entry edges to every member, the default agent marked) and `create_handoff_tool(agent_name=)` in an agent's tools are read as declared routes; LangChain `create_agent` is detected; a `model=` passed through a module-level chat-model binding, `tools=TOOLS` and `ToolNode(TOOLS)` are resolved within the file. The console prints each agent graph as a bounded flow (entry, routes with branch/goto/handoff notes, subgraphs, tools and model per node, unresolved routes). Framework-agent ids are scoped to the scanned project, the project agent `contains` its top-level graphs, and the CLI graph export folds non-delegating constructs into the project agent as the unified graph does. The framework node now links to the scanned, pinned package (previously a versionless copy, so CVEs on `langgraph` did not reach LangGraph agents), and declared wiring no longer counts as runtime-observed activity on attack paths. - MCP `scan` takes `project_path` to scan a repository directly; the path must resolve inside the home directory or `AGENT_BOM_MCP_WORKSPACE_ROOTS`, and project discovery runs off the event loop. - Opt-in runtime enforcement (`--injection-mode enforce`, the matching environment variables, policy key and Helm value): poisoned tools are removed from `tools/list` and later calls to them are refused for the session; injected tool results are replaced by a JSON-RPC error that names the detector and never forwards the injected text. Every action is audited with `action: blocked|stripped`. See `docs/RUNTIME_FAIL_MODES.md`. - `agent-bom cloud databricks`, `snowflake`, `huggingface`, `ollama` and `posture`, previously reachable only through `agent-cloud`. - Helm: an ingress-only NetworkPolicy for the control-plane API and UI that admits their namespace and the ingress controller (`controlPlane.networkPolicy`). - Persisted runtime, proxy and gateway activity appears in the graph as `recorded_activity`, with source receipts, replay-safe counts and exact tenant/cloud-scoped identity binding. One bounded UTC window covers both evidence stores. Unmatched identities remain unverified shadows; recorded decisions do not establish execution or permission and never form attack paths. - Agent contributor skills `.agents/skills/develop` (test-first loop) and `.agents/skills/secure-change` (security rules), loaded by Codex and Claude Code; CI now fails a PR that changes Python source without a test change (maintainer label `no-tests-needed` waives it) and scans every repo `AGENTS.md`, `CLAUDE.md` and `SKILL.md` with the skill auditor. - Contributor path: `GOVERNANCE.md` with the triager, reviewer and maintainer ladder, `MAINTAINERS.md`, and a Codespaces dev container that installs the dev extras and pre-commit hooks. - GitHub Action: `sbom-artifact` (`cyclonedx` | `spdx` | `none`) uploads an SBOM / AI-BOM workflow artifact; `mcp-gate` fails a pull request that adds or redefines a blocked, malicious or vulnerable MCP server; `max-annotations` caps annotations with an explicit "N more" notice. The job summary lists the top findings (severity, file:line, rule, fix), and the PR comment ranks findings by severity, then blast radius. - A reusable workflow (`.github/workflows/agent-bom-reusable.yml`), GitLab CI, Azure Pipelines and Bitbucket Pipelines templates under `examples/ci/`, and a GitHub Action guide with quick-start, full PR gate and new-findings-only examples. - Source-built language runtimes are detected in images (PHP, Python, Node.js, Go, Ruby, Java from image config) and on hosts and VM snapshots (`/usr/local` and `/opt` builds), and matched through NVD CPEs. Offline, a runtime reports a coverage gap, never a clean result. - Operator advisories match before feeds publish: `agent-bom db advisory add|list|remove|match`, `/v1/intel/operator-advisories` and MCP `intel_lookup`. Declared advisories match the newest stored scan per target, tenant-scoped; a later feed record with the same id or alias supersedes it. - NVIDIA GPU stack detection in `fs` scans, VM side-scans and image layers: driver, CUDA toolkit and NVIDIA Container Toolkit versions with NVD CPE identities, so their CVEs match GPU nodes. - Skill audits flag hardcoded secrets (type and line only), environment-variable exfiltration to a network sink, and instructions hidden in Unicode tag characters or variation selectors. - The agent-bom plugin installs in Codex as well as Claude Code, with `checkup`, `affected`, `bom` and `activity` skills. `agent-bom-guard` adds a Claude Code `PreToolUse` check that blocks known-malicious and typosquatted package installs. Both plugins publish a privacy policy. - `/v1/graph/attack-paths` accepts `kev=true` with the same meaning as MCP `exposure_paths`, and rejects undeclared query parameters with 422 instead of ignoring them. - `/health` reports `demo_seed: pending|complete` in demo mode, and the UI waits for seeding before showing counts. - Over HTTP or SSE, host-local MCP tools (`agent_activity`, `browser_extension_scan`, and `inventory` / `tool_risk_assessment` without `config_path`) are refused unless `AGENT_BOM_MCP_ALLOW_HOST_LOCAL_TOOLS=1`; stdio is unchanged. - `agent-bom activity`, the `agent_activity` MCP tool (audit profile, local and read-only) and the plugin `activity` skill review local Claude Code and Codex session history: MCP server and tool usage, configured servers never called in the window, risky actions with redacted evidence (pipe-to-shell, destructive commands, writes outside the project, secret-file reads, package installs) and installed packages. Reads are streamed and capped; prompts and responses are never read into results, and nothing is sent unless `--check-packages` is set. Sessions map to the shared trace span shape as local providers `claude-code-sessions` and `codex-sessions`, and used servers come from the runtime trace projection with exact discovery bindings; the control-plane pull route rejects these providers. - `agent-bom db update --source nvd` ingests NVD-only CVEs and their CPE ranges without an API key: a 14-day `lastModified` window at 5 requests per rolling 30 seconds (120 days and 50 per 30 seconds with `NVD_API_KEY`), so a source-built runtime such as `php 8.3.30` matches a CVE NVD has analysed before OSV or KEV list it, with the range's fixed release. - Operator advisories that name a `cpe_product` no longer report distro packages of that product as clean: Debian `php8.2-cli 8.2.29-1~deb12u1` against a `php:php` advisory takes the local Debian/Alpine/RHEL feed verdict when one exists, and is otherwise listed as `indeterminate` (`distro_backport_unverified`, shown in the `db advisory match` table) instead of comparing backported versions to upstream ranges. The daily re-match counts these as `indeterminate_distro` without freezing its cursor. - Helm: optional `nvdApiKey.existingSecret` injects `NVD_API_KEY` from an existing Kubernetes Secret (`secretKeyRef`, unset by default) into the scanner CronJob and control-plane API; the chart never takes a plaintext key. - "Am I affected by CVE-X?" on every surface: `GET /v1/intel/advisories/{id}/affected`, the read-only MCP tool `affected_assets` (graph profile) and `agent-bom db advisory affected ` return one answer per asset for a declared advisory or a local feed record, NVD CPE ranges included: affected (with the patch target), possibly affected (distro packages; verify the distribution's advisory) or not affected, with provenance, last observed scan and graph node ids for blast radius. Pages use a generation-carrying cursor (409 when the answer changed, 422 when malformed); `clean_scanned` means not found in what was scanned, never safe. - Operator-advisory and feed re-match matches are persisted as findings (tenant-scoped, one per advisory, package and asset) so they appear in `/v1/findings`; a rescan that no longer matches, a feed record that now covers the package at scan time, or a retired advisory resolves them. Possibly-affected rows keep severity `unknown` with `advisory_severity` alongside, so they are never counted as confirmed vulnerabilities. Control-plane scan graphs give declared advisories a vulnerability node and a `vulnerable_to` edge from the package. - Scans report distro packages of a CPE product (Debian `php8.2-cli` for PHP2Shell, CVE-2026-109618/109619) as possibly affected (`distro_backport_unverified`) when no distro record decides the CVE: JSON `possibly_affected`, SARIF note-level `agent-bom/possibly-affected`, CycloneDX `analysis.state: in_triage`, HTML and terminal. They are never counted as vulnerabilities and never trip `--fail-on-severity`. - Dashboard: an Advisories page to declare an emergency advisory (validation errors shown per field) and see which assets an advisory affects, with patch targets, distro "possibly affected" labelling and blast-radius links; the advisory freshness widget shows partial and stale feeds per source, and `/v1/intel/sources` reports a partial NVD sync as `partial` with its reason. - GitHub Action: optional `nvd-api-key` input (pass `${{ secrets.NVD_API_KEY }}`), set only as the scan step's `NVD_API_KEY`, so the default DB refresh, which includes NVD, reads the keyed window. Possibly-affected results stay in the SARIF upload as notices, outside `vulnerability-count`, the badge, the grade and gates. - Claude Code and Codex `affected` skill answers NVD-only CVEs as affected / possibly affected (distro) / not found in what was scanned, using `affected_assets` when a control plane is connected. New runbook `docs/RESPOND_TO_A_NEW_CVE.md`: declare, match, blast radius, patch, verify by rescan. - Source import discovery identifies Google ADK, Claude Agent SDK, Strands Agents and Azure AI Agents in Python and JavaScript/TypeScript, plus Bedrock AgentCore, Microsoft Agent Framework and NVIDIA NeMo Agent Toolkit in Python, and OpenClaw plugin-SDK imports in JS/TS. SDK package identities and AST labels agree, while near-name modules and general cloud clients are excluded. Static import evidence does not imply runtime execution. - Gateway operators can configure upstream HTTP connection/keepalive limits, timeout, circuit failure threshold and cooldown through CLI flags or matching environment variables. The existing validator rejects invalid settings before discovery or listener startup; authentication and policy defaults are unchanged. - Gateway replica sets can share one Postgres audit outbox (`AGENT_BOM_GATEWAY_AUDIT_BACKEND=postgres`, Helm `gateway.auditBackend: local|postgres`): events are claimed with database-clock leases, acknowledged with fenced deletes, and a tool call is admitted only after its own decision is durably acknowledged by the control plane (up to 20 seconds; the earlier replica-local spill remains the default). See `docs/RUNTIME_FAIL_MODES.md`. - The stdio proxy detects tool definition drift under a stable tool name (description, input/output schema, annotations), coalesces `notifications/tools/list_changed` refreshes and bounds the catalog it re-reads (20 pages, 4,096 tools); an incomplete catalog never replaces the baseline. - Gateway `--injection-mode enforce` remembers the tools it withheld from `tools/list` per tenant and upstream (bounded, 24 h TTL) and refuses a later `tools/call` to them with the same `-32001` error and an audited `action: blocked` event; a clean relisting restores the tool. The memory is per process: a replica that never saw the listing forwards the call and still inspects its result (`docs/RUNTIME_FAIL_MODES.md`). - `AGENT_BOM_MAX_IMAGE_CONFIG_BYTES` (default 16 MiB) bounds the image config blob read during a registry pull separately from the manifest limit; an oversized config fails the scan before any layer is fetched. ### Changed - Image scans stream layers instead of buffering them: peak traced memory for a 1 GiB image fell from about 3 GB to 9 MB. A time budget (`AGENT_BOM_OCI_SCAN_TIMEOUT_SECONDS`, default 900) and member, size and decompression limits report a `partial` scan that names the skipped layers instead of exhausting the host. - Fix First explains each priority (for example "P3: high severity; not known exploited, no credential reach"), the AI component summary no longer calls a clean or empty scan "safe", and Findings rows leave remediation cells blank instead of printing filler. - The Docker Hub push token is available only to release jobs in a `docker-release` environment; pull-request CI uses a pull-only token. Main-failure alerts react only to pushes to this repository's main branch. - Compose files publish ports on loopback by default, including the development Postgres and Redis and the runtime example proxy. - GitHub Action: `pr-comment` defaults to `auto` (posts when the token has `pull-requests: write`, otherwise skips with a notice); annotations are error, warning or notice by severity; `format: json` writes `agent-bom-results.json`; docs reference `@v0` and `scan-type: scan`. - PR CI sizes pytest workers to the runner, skips smoke when the full shards replace it, and splits UI E2E across four runners. - Migration `20261023_02` revokes writes on `alembic_version` from the application and RLS-maintenance roles; migrations run as the admin role. - `agent-bom image ` and `scan --image` now contact the image's registry first (read-only GETs, plus a token request) instead of the local Docker daemon. A reference without a registry host that the local daemon already holds (`acme/app:dev`) is scanned from the daemon, so it never resolves to a same-named Docker Hub image; other local-only tags scan through the daemon after the registry pull fails; use `--pull-mode daemon` to never contact the registry. `--offline` never contacts a registry. - Hardcoded secrets found inside an image are high/critical findings, so an image that bakes in a credential now fails the default severity gate. - `agent-bom image ` works without a Docker daemon: it pulls the manifest, config and layers over the OCI distribution API (anonymous, Docker Hub token flow, `~/.docker/config.json` `auths`, `credHelpers` and `credsStore`, or `--registry-user`/`--registry-pass`), picks the platform from an index (default `linux/amd64`, `--platform` to choose), verifies every manifest and blob digest, and streams each layer through the same bounded walk as `docker save` archives. `--pull-mode auto|registry|daemon` (`--image-pull-mode` on `scan`, `AGENT_BOM_IMAGE_PULL_MODE`); `auto` scans a host-less reference held by the local daemon from the daemon, and otherwise uses the daemon only when the registry pull fails and says why. zstd layers are reported as coverage gaps. - Image signatures and attachments: cosign signatures (`sha256-.sig`) are verified with `--cosign-key`/`--image-cosign-key` (ECDSA, RSA or Ed25519 public keys); keyless Sigstore signatures are verified with the optional `sigstore` extra when `AGENT_BOM_IMAGE_SIGNER_IDENTITY` and `AGENT_BOM_IMAGE_SIGNER_ISSUER` name the expected signer; signatures without a key or a signer policy are reported as `present-unverified`, never `verified`. OCI referrers (referrers API, tag schema, cosign `.att`/`.sbom` tags, BuildKit attestation manifests) are listed as SBOM / provenance / attestation / signature. Status `verified`/`invalid`/`present-unverified`/`unsigned`/`unknown` is on the image agent's metadata, the graph image node and the console; `--require-signature`/`--require-image-signature` fails the scan unless the signature is `verified` with a cosign public key. - Secrets inside images: text files in every layer (same matchers, skip rules and redaction as `agent-bom secrets`; binaries, OS package trees and files over `AGENT_BOM_IMAGE_SECRET_MAX_FILE_BYTES` skipped; at most `AGENT_BOM_IMAGE_SECRET_MAX_FILES` per image), image config `ENV` values and build history (`created_by` build args) are scanned. Findings are `CREDENTIAL_EXPOSURE` bound to the image node with the layer digest; a secret a later layer deleted is still reported (it is in the layer blob) with `in_final_filesystem: false`. - Base-image attribution: the base named by the OCI `org.opencontainers.image.base.name`/`.base.digest` annotations or labels is fetched (server-side scans only from `AGENT_BOM_REGISTRY_ALLOWLIST`, or the image's own registry without one), and when its layers are an exact prefix of the image's, each package occurrence is marked `layer_origin: base|app` with the base name. A named base whose layers do not match attributes nothing. - `agent-bom iac` scans Docker daemon configuration (`daemon.json` in a `docker/` directory, or any `daemon.json` named on the command line) with eight `DOCKERD-*` rules: TCP API without `tlsverify`, non-loopback insecure registries, `icc` not disabled, no `userns-remap` (not required for rootless), `live-restore` off, `no-new-privileges` off, `experimental` on and `log-driver: none`. Missing keys take dockerd's default. - Compose rules `COMPOSE-007`..`011`: seccomp/AppArmor `unconfined` or `label:disable`, host IPC/UTS/user namespace, sensitive host paths bind-mounted (`/`, `/etc`, `/proc`, `/sys`, `/var/lib/docker`, `.ssh`, ... but not `/etc/localtime` or app directories), `user: root`, and services without `no-new-privileges`. `COMPOSE-005` also covers `SYS_MODULE`, `SYS_PTRACE`, `SYS_RAWIO`, `DAC_READ_SEARCH`, `SYS_BOOT` and `BPF`. - Dockerfile rules `DOCKER-023`..`026`: `apt install` without `--no-install-recommends`, apt/apk packages without a version pin, a `CMD`/`ENTRYPOINT` overridden later in its stage, and credential files (`.env`, SSH private keys, `.npmrc`/`.pypirc`/`.netrc`, keystores, `.aws/credentials`, `.docker/config.json`) copied into an image layer. - `*.dockerfile`, `*.containerfile` and `Containerfile*` are scanned as Dockerfiles. - GPU node pools in cloud inventory, read-only: EKS managed node groups (`eks:ListNodegroups` / `DescribeNodegroup`), GKE node pools with accelerators, GPU sharing, MIG partition and driver-install setting, AKS agent pools with GPU VM size, MIG profile and driver opt-out, GCE guest accelerators, Snowflake SPCS compute pools (`SHOW COMPUTE POOLS`, GPU model and count per `GPU_*` family) and Databricks GPU clusters (kept even without installed libraries). Connection inventory summaries report `node_summary.gpu_node_pools`. - GPU pools in the graph: a `gpu_node_pool` cloud resource contained by its cluster and assuming its node IAM role or service account; GPU attributes on EC2, GCE and Azure GPU instances; SPCS compute pools under their account. - `--gpu-scan` and the MCP `gpu_infra_scan` tool inventory Kubernetes GPU workloads with read-only `kubectl get`: node pool, service account, EKS IRSA role, privileged / hostPath / host-namespace settings, the node driver (GPU Feature Discovery labels) and Container Toolkit (GPU Operator `ClusterPolicy`). The driver and toolkit become CPE-identified packages matched like any other, and attack paths run from a vulnerable host GPU stack through the workload to its service account, IRSA role and the GPU node identity. - Provider-aware GPU posture checks GPU-001 to GPU-021 (SSH open on EKS GPU node groups, AKS node public IPs, GKE default compute service account, untainted EKS/AKS GPU pools, operator-managed drivers, shared GPUs and multi-tenant time-slicing, privileged / hostPath / host-namespace GPU pods, Databricks no-isolation GPU clusters, shared SPCS GPU pools) in the unified findings stream and the graph. - Image scans record model files found in layers and statically disassemble pickle-bearing ones (never deserialized) within the existing pickle byte cap, honouring whiteouts; findings attach to the image. See `site-docs/features/gpu-ai-infrastructure.md`. - The README banner shows coverage in six groups (AI clients and IDEs, AI platforms and model hubs, GPU and neo clouds, hyperscalers and Kubernetes, data and vector stores, identity/SaaS/dev) plus where evidence can be sent, built from `docs/images/integrations-manifest.json`. Every entry names the code that implements it; a test fails when an entry has no implementation or a registered provider, connector or MCP client is missing. The same generated table appears in the README, PyPI and Docker Hub pages and the docs index. ClickHouse is listed as an analytics and export destination, not a scanned source. - Graph glyphs: packages now draw a blocks glyph and the container keeps the shipping-container glyph, so a package hop never reads as a container. The path step list (desktop and phone) draws each hop's own entity glyph instead of a coarse role glyph, so containers no longer share the MCP server glyph, users no longer share the agent glyph, and environments and clusters no longer share one glyph. - Scan-job `result` and `result_document` values of 4 KiB or more are stored zstd-compressed behind a versioned, SQL-visible header instead of as uncompressed JSON rewritten on every job update; top-level job keys and the demo-estate SQL projection keep working, and a guard test rejects any new SQL that reads deeper into a stored result. Measured on the demo estate in `docs/perf/report-volume.md`. - Dashboard runtime activity is grouped by origin, collector, session and identity, and connection-state copy says what was recorded rather than what is live. - Server-side disk side-scans require a tenant connection grant that names the provider, account, target and collector; live-Kubernetes collection is an explicit opt-in; API-docs assets are pinned with integrity hashes. - Shared Postgres gateway audit delivery: non-admission events are enqueued and the delivery worker is woken, instead of flushing inline under the send lock, so a slow control plane no longer serialises every tool call behind a 20 s send; admission still waits for its own durable acknowledgement. - Tool definition drift fingerprints ignore the order of schema `required`/`enum` sets and declaration `icons` lists and treat absent `annotations` as `{}`; literal values, vendor metadata, `anyOf`/`oneOf` member order and `required` membership still drift. - Pushed scan results publish detached snapshots to the in-memory job store, keeping concurrent graph readers stable during enrichment. A fatal graph roll-up warm-up exit releases its worker state without suppressing the error; later readers compute uncached views. - In enforce mode the stdio proxy drops non-JSON-RPC upstream stdout whether or not inline scanning is enabled, and audits the drop; `--injection-mode --help` states which detections block (high/critical response-inspector categories) and which forward with an alert. - `AGENT_BOM_REGISTRY_ALLOWLIST` accepts any Docker Hub alias (`docker.io`, `index.docker.io`, `registry-1.docker.io`) for Hub images, and when an allowlist is set the bearer-token realm host must be the registry itself or allowlisted. - Advisory re-match indexes advisories by package identity and CPE product once per run (5,000 packages × 2,000 advisories: 10.4 s → 0.12 s, identical results) and, when scan snapshots are enabled, reads only the newest job per scope instead of decoding every historical result. - `compare_version_order` maps vendor and OSV ecosystem labels (`Ubuntu`, `Debian:12`, `Alpine:v3.18`, `Red Hat`, `Rocky Linux`, `AlmaLinux`, `SUSE`, `Wolfi`) to their distro comparator; previously such labels fell through to PEP 440 ordering and could compare distinct releases as equal. - Alembic refuses to run as `agent_bom_app` or `agent_bom_rls_maintenance` (the migration that makes `alembic_version` read-only would otherwise revoke the runner's own access); use the admin `ALEMBIC_DATABASE_URL`. Migration `20261027_03` is guarded and builds its index concurrently; `alembic downgrade` cannot pass below `20261027_02` (`docs/STORAGE_BACKENDS.md`). - The release `docker-mcp-pin` job fails loudly, with a run-summary section and the manual commands, when the automation signing key is missing instead of silently leaving the published pins at the previous version. ### Fixed - Hugging Face collection failures return stable outcome codes (`denied`, `throttled`, `unavailable`, `empty`) and keep the partial inventory instead of failing the whole cloud scan. - Corrupt or truncated gzip SBOM payloads are rejected as validation errors instead of raising inside the parser (ClusterFuzzLite regression). - `HELM-003` no longer reports the `key`/`name` fields of an `existingSecret`, `secretKeyRef` or `valueFrom` block as a hardcoded secret, so a chart that references a Kubernetes Secret the documented way (including this project's `nvdApiKey.existingSecret`) passes the default gate. - `contracts/v1/scan-report.schema.json` accepts the `blast_radius` schema `"2"` rows and the scan-wide `coverage_warnings` rows (`kind: remote_lookup_error|remote_lookup_gap|package_version_gap`) that every 0.111.0 report carries; a report with findings now validates against the shipped contract. - Behind an egress proxy (`HTTPS_PROXY`) on a network without direct DNS, advisory and registry lookups no longer fail with `host unresolvable or egress refused`: the proxy resolves the name, so a local resolution failure is not treated as a verdict. Literal private and metadata addresses, and `NO_PROXY` hosts, are checked as before. - Shared Postgres audit admission drains a backlog larger than one delivery batch (after a control-plane outage) within the acknowledgement deadline instead of returning 503 until the retry worker catches up; a cursor minted for another tenant on `/v1/intel/advisories/{id}/affected` is `422`, as on every other paged route; `GET /v1/intel/advisories/{id}/affected` and `/v1/graph/attack-paths/cross-vendor` reject undeclared query parameters with `422`. - Source-only projects (no manifest or lockfile) now get a project host agent, so LangGraph builders fold under `contains` edges and `code_agents` the same way as projects with a `requirements.txt`; previously every construct scanned as a standalone agent. - `init.sql` bootstrap carries `trend_history.kev_count`, matching migration `20261022_01`; the gateway audit outbox grants `agent_bom_readonly` SELECT in both schema paths. - Stdio proxy: the catalog refresh and the client relay share one stdin writer lock, so a `tools/list_changed` refresh under backpressure no longer races the relay's drain on Python 3.11 and kills the session. - Version ordering for `/etc/os-release` style labels (`Debian GNU/Linux`, `Alpine Linux`, `Red Hat Enterprise Linux`, `Ubuntu 22.04`) routes to the distro comparator; previously such labels fell through to PEP 440 and could compare distinct revisions as equal. - Migration `20261027_03` drops and rebuilds its partial index when an earlier `CONCURRENTLY` build was cancelled and left it `INVALID`, instead of keeping the invalid index and marking the schema version as upgraded. - Retain package/ecosystem identity and credential-name redaction in the dedicated MCP AI inventory tool. - Preserve validated sub-second upstream timeouts, disabled keepalive pools, and zero circuit cooldown in the gateway relay. - Enable AI SDK inventory automatically for supported non-Python source trees, retaining package identity and source locations across project and repository scans. - Graph times report when evidence was recorded, never when it was read. Governance overlay nodes and edges (managed identities, JIT grants, conditional-access policies, blueprints, drift incidents) take their times from their own records instead of the request clock, a graph loaded from Neptune keeps its snapshot time, and a scoped consequence graph keeps its source graph's time. - On Python 3.11, registry-latest lookups no longer start a second request before the first npm 429 opens the cooldown: the 3 s lookup deadline runs in the caller's task (`asyncio.timeout`) on every supported Python. - The same scan now builds the same graph. A node or edge built without its own time takes the scan's recorded time (the report's `generated_at`, or the stored snapshot's time) instead of the clock at the moment it was built or read, so two builds of one report are identical and no time claims an observation at build time. Finding nodes keep the first observation their findings recorded, audit-observed edges keep the aggregate's `last_seen`, a node seen by several sources spans the earliest first and latest last observation (previously the last source overwrote `last_seen`), and the demo estate stamps its snapshot time. Graphs carry the scan's time as `observed_at` (used for node and edge times and for edge freshness), while a stored snapshot's `created_at` stays the time it was stored, so retention never prunes a freshly imported report whose scan is old. A guard fails CI when a graph container is constructed without its observed or created time. - Building the graph for a server shared by many agents no longer re-sorts the server's agent and alias lists once per agent: 2,000 agents sharing one MCP endpoint build in about 1 s instead of 3.6 s, with identical output. - Version ordering no longer reports installed versions as past a fix they have not reached, which hid real CVE matches in four ecosystems. RPM compares `[epoch:]version` before the release as `rpmvercmp` does, so `2.4-12.el8` is affected by a `2.4.1-1.el8` fix (RHEL, Rocky, Alma, SUSE). crates.io/Cargo, Pub, Hex and Swift packages use SemVer 2.0 precedence instead of PEP 440, so `1.0.0-test.1 < 1.0.0` and `canary.1 < canary.2`. Go ignores `+incompatible` as build metadata (`v2.0.0+incompatible` equals `v2.0.0`) and orders pseudo-versions as the pre-releases they are (`v1.5.0-0.- < v1.5.0-rc.1`). PyPI dash-spelled `-dev1` / `-post1` releases normalise as PEP 440 requires (`4.2.0-dev1 < 4.2.0`), and local labels such as `+r1` are left untouched. - Tenant isolation: the legacy SQLite backfills for agent identities and fleet agents rewrote rows by id alone, so two tenants sharing an agent id could overwrite each other's agent data. Both are tenant-scoped, and a guard fails CI on any SQLite write to a tenant-keyed table that filters by id without the tenant. - `.csproj` parsing refuses XML entity declarations instead of expanding them, and `defusedxml` is a declared dependency. - "Am I affected by CVE-X" answers from every alias record of a vulnerability. A CVE row that carries only distribution ranges no longer hides the PyPI, npm or Maven range on its GHSA alias, GHSA ids match regardless of case, and the advisory takes the worst severity across its records. Packages the scan itself flags (urllib3 for CVE-2023-43804, django for CVE-2022-34265, pillow for CVE-2023-4863) are now reported affected instead of clean. - Dependency accuracy on real repositories: Gradle versions given as `$var`/`${var}` resolve from `gradle.properties` and `ext` blocks, and builds without a lockfile report partial coverage; `setup.cfg` and static `setup.py` dependencies are read (setup.py is parsed, never executed); requirement specifiers keep the whole range and environment markers; members of a lockfile-owned pnpm/npm/yarn workspace are no longer re-resolved to invented versions; Maven modules inherit local parent POM dependencies and managed versions; go.sum checksum verification reads the checksum database format and case-encodes module paths; go.mod `replace` blocks parse correctly; OSV records that enumerate git-tag versions no longer produce unverified matches. - Health probes stay up when Postgres is down or stalled: probes bypass the shared rate limiter, the limiter falls back to memory when its store errors or is slow, database outages return a JSON 503, `/readyz` gives up after 3 s, and every chart probe sets `timeoutSeconds`. A request waits at most `AGENT_BOM_POSTGRES_POOL_TIMEOUT_SECONDS` (default 10) for a pooled connection instead of psycopg_pool's 30 s per attempt. - API keys configured by the operator (`AGENT_BOM_API_KEYS`, the key file, `configure_api`) no longer expire after 30 days and no longer add a row on every boot; removing one from configuration revokes it. Without Postgres, keys minted through the API persist in the SQLite database instead of process memory, and mint, rotate and invitation responses report whether the key is durable. - `agent-bom cloud aws|azure|gcp` without the provider extra stops before any discovery and prints the one install command. - Databricks: model-serving endpoints and cluster libraries are inventory, not unauthenticated MCP servers (no more HIGH authentication findings on platform-managed endpoints); best-practice findings carry their workspace, so two workspaces no longer merge into one asset; audit-log delivery reports no data, not a critical error, when only workspace credentials are available. - Light theme: notices that used near-white text are readable, and a guard forbids pale text without a dark-theme variant. The MCP catalog shows 25 servers per page. - Registry documentation identifies temporary cloud resources created by opt-in disk side-scans and links the required secret bootstrap before production Helm installation. The docs landing page uses the verified reference lab instead of an unverified illustrative package/fix pair. - Persisted tool-drift baselines are scoped to an explicit server identity and written atomically. Sessions without that identity keep their baseline in memory; legacy shared files are not assigned to an inferred owner. - Release preparation keeps OpenClaw pull and signature-verification commands on the published version until artifacts are available; repeated version generation and validation agree. - Runtime evidence retains bounded actor/session/cloud attribution, preserves available evidence when another store fails, and orders timestamp offsets in UTC. Structured graph IDs survive redaction while embedded credentials and shortened identities cannot bind. - Databricks discovery retains resolved workspace scope and serializes incomplete security evidence without converting collection errors into passes. Workspace-user observations do not establish account-wide coverage. - Malicious skill findings fail the default CLI gate; explicit audit mode retains a non-blocking review path. - `agent-bom db update` shows NVD progress live: each `lastModified` slice with its date, the running record count and every rate-limit wait. Keyless NVD runs stop after a wall-clock budget of 8 minutes (`--nvd-time-budget SECONDS`, `AGENT_BOM_NVD_TIME_BUDGET_SECONDS`, `0` = no limit; keyed runs have none by default) as `PARTIAL` with `partial_reason: time_budget`, keeping the window checkpoint, and the summary says how to resume. The start-of-run note now describes the progress each selected source actually reports instead of saying "live progress follows" only for OSV. - Keyless `agent-bom db update` no longer spends up to about 100 minutes on the NVD CVSS/CWE backfill: it makes at most 50 per-CVE requests per run, and rows whose CVE the `lastModified` window already scored take that score locally without a request. Keyed runs are unchanged. - `/v1/graph` `stats.attack_path_count` now equals the `/v1/graph/attack-paths` total for topology-only snapshots instead of reporting 0. The node page reads the snapshot path index (one COUNT/MAX query, cached per tenant, scan and snapshot generation) and never loads the graph; a snapshot without a current index reports the queue's derived total once the queue has been read, and `stats.attack_path_count_basis` says which count (`queue_total` or `persisted_paths`) is shown. - `agent-bom db update` now includes NVD by default (newest first, incremental), so CVEs published only in NVD, such as PHP2Shell (CVE-2026-109618/109619), reach the local database without `--source nvd`. - `agent-bom db update --source nvd` with `NVD_API_KEY` read only the oldest 1,000 records of a 120-day window (about 91,000 modified CVEs) and printed `complete`, so the newest CVEs never landed. The window is now walked newest first in day slices, keyed runs cover the whole window by default (keyless runs read up to 60,000 records), the checkpoint records covered ranges so later runs fill the older tail without re-reading, and a capped, rate-limited or timed-out run shows `PARTIAL` in `db update`, `db status` and `db freshness`. - The SSE/HTTP proxy (`agent-bom proxy --url`) now reads every page of the upstream `tools/list` before applying `--block-undeclared`; tools declared after the first page were blocked as undeclared. - Proxy tool-drift detection reads a paginated `tools/list` (`nextCursor`) as one catalog instead of comparing each page with the first, so a multi-page server no longer raises false "new tools" and "tools removed" alerts. A listing that stops early (20-page cap, repeated or invalid cursor) is marked incomplete: it never becomes the baseline and never reports removals. - Gateway drift enforcement looks up open incidents for the caller's own blueprint in the store (SQLite and Postgres, with a new index and Alembic revision `20261024_01`). Previously a tenant with 200 or more open incidents on any blueprints got `unavailable` for every lookup, which denied every call in secured enforce mode and dropped to audit-only otherwise. - The `ai-enrich` extra requires `litellm>=1.96.2`, the first release clear of every LiteLLM advisory on OSV, including CVE-2026-84377. The lockfile already used 1.100.1; the floor stops a pip resolve from landing an affected version. - Graph UI: a selected path title wraps before an advisory id (CVE, GHSA, OSV) instead of splitting it across lines; relationship labels stay inside the canvas after the node stepper or a pan moves the view, never cut at its edge; and the snapshot selector shows its full label when there is room, otherwise an ellipsis with the full label on hover. - IaC findings can be accepted one at a time with an inline `agent-bom: ignore[RULE-ID] ` marker on the offending line or the line above; a marker without a reason suppresses nothing, and accepted findings stay in the scan result's `suppressed` list. The reusable workflow uses one for its deliberate `@v0` action reference, so the repository's own scan passes. - GitHub Action: the default scan covers the checkout, so Terraform, Kubernetes, Helm, CloudFormation and workflow files are scanned and the runner's home-directory MCP configs no longer leak into CI reports. - GitHub Action: `scan-type` `image`, `fs`, `sbom`, `iac`, `secrets` and `code` no longer exit 2 with default inputs; only flags the selected command accepts are passed, and gates it cannot enforce fail with an error. - GitHub Action: `baseline` passes `--delta` instead of the nonexistent `--delta-mode`, and `--baseline --delta` now suppresses pre-existing IaC, secret, skill and other non-CVE findings, matched without line numbers. - GitHub Action: the vulnerability database cache uses the real path (`~/.agent-bom/db/vulns.db`) with a daily key, `setup-python` no longer fails on repositories without Python manifests, and inputs reach run scripts only through `env`. - Terraform IAM wildcards are detected in `jsonencode` policies, `aws_iam_policy_document` data sources and the `"*:*"` form, at the offending line; Deny statements are not flagged. TF-SEC-010 now covers service-wide grants such as `s3:*`. - Terraform public S3 detection reads `aws_s3_bucket_acl` and flags an `aws_s3_bucket_public_access_block` with any flag set to false; a block for another bucket no longer covers every bucket. TF-SEC-001 accepts a separate `aws_s3_bucket_server_side_encryption_configuration`. - Docker Compose files are scanned (privileged, Docker socket mount, host network or PID, ALL/SYS_ADMIN capabilities, literal secrets in environment by variable name only). A named file no rule module evaluates now reads "not evaluated" instead of "no misconfigurations". - GitHub Actions hardening gaps are real findings with rule ids, lines, SARIF results and the severity gate: `pull_request_target` checking out the PR head (GHA-001), actions not pinned to a commit SHA (GHA-002), untrusted `${{ github.event.* }}` input in `run:` (GHA-003) and `write-all` or missing top-level permissions (GHA-004). - Kubernetes findings report the line of the offending key (hostPath, image, missing limits, probes, env secrets, capabilities) instead of line 1, including in multi-document manifests. - Helm chart templates are evaluated: rendered with `helm template` and default values when `helm` is on PATH, otherwise scanned textually for privileged and host-namespace keys, with coverage stating that rendering was skipped. Templates no longer count as a clean Kubernetes scan. - Duplicate rules no longer report one issue twice: TF-SEC-008 and CFN-013 are retired, DOCKER-004 covers only local `ADD` and DOCKER-010 only tagged images without a digest. Probe, HEALTHCHECK, logging, retention and versioning rules are rated low. - Display redaction no longer hides boolean settings such as `automountServiceAccountToken: true.`. - SARIF results for skill and instruction files use the real relative path and line instead of ``, a redaction label is never emitted as an artifact URI, and SARIF tool links point at the current repository. The skill-audit report detail no longer includes the absolute host path. - `scan -p` still scans the project when `--image` or code paths are also given, including the default run with Semgrep installed. - The hub partition runway job logs the expected DDL permission denial as one line instead of a traceback. - Graph exports and graphs rebuilt from a report name a cloud asset with the node id and entity type its finding row declares (`node_id` with `entity_type`), in both the finding and the CIS-benchmark projections, instead of re-deriving `cloud_resource::`. The showcase job's graph export now joins the showcase snapshot on 727 cloud-resource and data-store nodes (previously 3) and on 1,233 nodes once the roles, clusters, service accounts and principals, models, agents and servers the rows declare are counted (previously 18). That includes the 12 multi-source compute VMs under their merged `cloud_resource:aws:aws_instance:…` id rather than the posture row's ARN, which stays the node's `resource_id`. Demo-estate findings now record their asset node's entity type. Buckets, databases and roles therefore no longer gain a `data_store:cloud_resource:…` companion in the export, and the ASPM overlay no longer attaches an asset whose kind the relationship contract does not let belong to an application. - The demo-estate showcase names its 5 agents, 10 MCP servers, 26 tools, 15 credentials and its provider with the ids a scan derives (`agent:cfg-:cursor`, `server:cfg-:cursor:`), so the showcase snapshot, `/v1/scan/{job_id}/graph-export` of the showcase job and `agent-bom scan --demo` join on every agent, server, tool, credential, provider, package and vulnerability id. The former short ids (`agent:cursor`, `server:shell-runner-server`, `cred:aws-secret`) resolve as node aliases; exposure-path ids through these nodes change. `scan --demo` no longer edits the shared demo inventory in place or derives agent ids from `$HOME`. - Snapshot diffs (`/v1/graph/diff`, `/v1/graph/changes`, MCP `graph_diff`) compare a node whose id scheme changed under its new id when the new snapshot records the old id as an alias. It is unchanged, or changed with a `previous_id`, instead of removed plus added; edges follow their endpoints. The demo showcase diff reports 3 removed nodes instead of 15. - While the demo estate is seeding, an unpinned `GET /v1/graph` returns 503 `current_estate_seeding` with `Retry-After` instead of an empty graph marked complete whose generation changes between reads. Pinned reads and the seed's own reads are unaffected. - Exposure-path ids include the per-hop relationships, identically on REST, MCP and the path payload, so two stored paths over the same hops through different relationships no longer share an id. Paths recorded without relationships keep their hop id. - `GET /v1/graph` and `/v1/graph/attack-paths` follow one cursor rule: the cursor carries the snapshot generation, so `snapshot_generation` is optional on a continuation and a mismatching one returns 409. `/v1/graph` no longer returns 422 for a cursor without the token, and attack paths no longer return 400 when a matching token is sent. - Graph exports join REST and MCP: `/v1/scan/{job_id}/graph-export`, `agent-bom graph` and `scan -f graph` use the canonical node id (`pkg::@`, `vuln:`, `agent:…`, `server:…`, `misconfig:…`) and an `entity_type` from the graph enum on every node. Display kinds such as `pkg_vuln` and `server_cred` stay in `kind` / `type`; the old package and advisory spellings stay in `attributes.legacy_id`. - An unpinned `GET /v1/graph` whose evidence changes during assembly rebuilds a bounded number of times, then returns 503 with `Retry-After` instead of 409. A pinned generation that changed still returns 409. - Feed re-match pages on (modified, id), so records sharing a timestamp are no longer skipped, honours an advisory's `limit_version` through the same range check as scan time, and marks a run `incomplete` when tenant or job caps are reached. - MCP `intel_lookup` reads advisories declared through the API when a store is configured. - Cross-vendor paths never report `has_more` with an empty cursor. Search ranks an exact id, id suffix or label first. - Every path-taking MCP tool returns the same validation error for a path outside the allowed roots, naming `AGENT_BOM_MCP_WORKSPACE_ROOTS`, instead of "An internal error occurred". `inventory` now applies the same check. Tool calls that return an error are logged and counted as failures. - The standalone `agent-bom mcp server` in demo mode reads the demo database. Image tarball scans no longer include the host's agents. - The overview vulnerability card counts with the query its link opens, so the card and the findings list agree. Demo trust scores use the 0–100 scale the scorer and UI use. Mixed-version issue titles read "ws · 2 versions". - Credential counts say what they count on every surface: held by the server, or exposed by the advisory's impact. - Graph nodes keep their canonical type, layer and evidence when types share a renderer; recorded evidence is no longer shown as runtime; advisory ids are never clipped. - Persona journeys: the remediation link no longer 404s, overview counts no longer change after first load, and a queue row no longer mixes two package versions. - CIS results come from the graph, and a control passes only with a recorded passing result; missing results are `not_evaluated` and excluded from the score. - Graph change exposures page their top rows, and removed paths link to the previous snapshot. - NVIDIA CSAF advisories attach only to the release branch they fix, and NVD ranges scoped to another platform are skipped. - Documentation and shipped manifests reference only CLI commands that exist (the proxy bootstrap bundles and the Kubernetes DaemonSet called removed commands); the check now verifies every word of a cited command. Version bumps update the OpenClaw, first-run and CloudFormation image pins. - `agent-bom serve` and `agent-bom api` exit when the Postgres control plane cannot initialize, instead of logging "lifespan appears unsupported" and answering every request with 500. The error names the missing migration or runtime-role grant. - `agent-bom scan -p --sbom ` scans the project's manifests and MCP configs as well as the SBOM. `-p` with `--no-discover` still discovers the project's own MCP configs, as MCP `scan` does with `config_path`. - Demo package nodes carry their name, ecosystem, version and purl, and no longer carry cloud exposure flags. Each demo scan's summary counts its own active findings, as the findings API does. Demo AWS accounts use only AWS documentation example ids. - zod updated to 4.6.7 for GHSA-mrhx-c7xc-m3w5 (development dependency). - MCP `scan`, `where`, `compliance`, `policy_check`, `runtime_correlate`, live `context_graph` and the local `blast_radius` fallback no longer read the server host's agent configs over HTTP or SSE without `config_path`; they return `AGENTBOM_MCP_AUTH_FORBIDDEN` unless `AGENT_BOM_MCP_ALLOW_HOST_LOCAL_TOOLS=1`. A `scan` of an explicit image, SBOM or package skips host discovery with a warning. - Cloud best-practice results imported from an external scanner are cloud posture, not vulnerabilities, so `domain=vuln` equals the overview Vuln / SCA card (the demo listed 788 against the card's 785). Rows stored under the old lane read as cloud posture too. - Advisory re-match past its tenant cap serves the tenants with the oldest attempt first, so every tenant is reached within ceil(tenants / cap) runs instead of the same alphabetical tail being skipped every run. - The remediation plan counts the credentials the affected servers hold (names only) beside the credentials exposed by the advisory's impact, in the API (`server_credentials`, `server_credential_count`; `null` when a finding did not record them), the remediation page, the scan result, console and JSON output. - `GET /v1/graph` bounds a page's stack and containment context at `completeness.context_limit` (`max(limit, 500)`), keeping the agent stack first, then ancestors from the top of the spine down; `context_omitted` and `context_truncated` report the cut. Every context node carries `context: true`, so ranked nodes are told apart; each node is ranked on exactly one page of a cursor walk, and context may repeat across pages by contract. On the demo, the default `limit=500` page drops from 1,548 to 1,321 nodes and keeps its org and account spine, and the first `limit=1000` page drops from 2,571 to 2,328. The UI's default 50-node page is unchanged. - The dashboard keys attack paths by the backend `exposure_path_id` (falling back to hops plus per-hop relationships), so two paths over the same hops through different relationships no longer share a selection, card or queue row. Graph change highlights carry `exposure_path_id`, their "Investigate" links select that exact path, and a path that differs from the previous snapshot only by relationship is reported as new. - While the demo estate is seeding, every unpinned current-estate read refuses with 503 `current_estate_seeding` and `Retry-After`, not only `GET /v1/graph`: attack and exposure paths, search, agents, rollup, node and impact reads, `POST /v1/graph/query`, `should-i-deploy`, `/v1/inventory/assets` and `/v1/inventory/summary`, plus MCP graph tools in the same process (`AGENTBOM_MCP_UPSTREAM_UNAVAILABLE` with `details.reason`). Previously 22 of these 23 reads answered 0 items with `complete: true` during the seed. Reads pinned to a recorded scan are still served, and the seed's own reads are never refused. - A graph read whose `scan_id` (or `scan`) names no snapshot of the caller's tenant returns 404 instead of 200 with no nodes and `complete: true`. This covers `/v1/graph` and the 14 sibling reads that served an empty page (agents, attack and exposure paths, clusters, governance, rollup, scoped, node neighbors, incident edges, fix-first, `should-i-deploy` and more); MCP `exposure_paths` and `should_i_deploy` return `AGENTBOM_MCP_NOT_FOUND_RESOURCE`. - `/v1/graph`, `/graph/search`, `/graph/agents` and `/v1/inventory/assets` reject a `cursor` sent with a non-zero `offset` with 400, as the attack-path queues do, instead of serving the cursor's page and echoing the ignored offset. - A cursor that does not decode, or that belongs to another tenant, query or replaced incident-edge page, is a 422 on every graph and inventory route. `/v1/graph`, the attack-path queues, incident edges and inventory assets returned 400, and `/graph/agents` returned 500. - Graph exports of an `--sbom` input or a project's repository inventory name them as the graph does (`source_file:sbom:…`, `directory:repository:…`, `directory:manifest:…`) instead of an agent, an MCP server and a `provider:sbom` / `provider:project` node the graph never draws. 6 export ids that joined nothing in a scan with both inputs now join. - The showcase snapshot places each demo code finding on the file it names (`source_file:` / `config_file:`, the ids a repository scan gives those files), and a finding row's declared `finding_node_id` names its node in report-built graphs. The showcase job's graph export now joins the showcase snapshot on all but 10 of 2,481 nodes (previously 45): the 8 data-store companions of Snowflake warehouses and the 2 tool-drift rows the showcase draws as `drift_incident` governance nodes. - AI source scans apply the shared placeholder policy to credential matches while retaining masked findings for non-placeholder values. - AI source scans detect OpenAI Agents SDK imports as `openai-agents` and reject similarly named Python modules such as `llama_index_helpers`. - CycloneDX vulnerability ingest into the compliance hub resolves `affects[].ref` against nested components and the metadata component, so a vulnerability on a nested library keeps its package purl instead of falling back to the bare vulnerability id. - Kubernetes manifest scans report a container as root (K8S-005) when `runAsUser: 0` or `runAsNonRoot: false` is set only in the pod-level `securityContext`, as live posture (K8S-LIVE-011) already did; a container-level value still overrides the pod's. Privileged containers (K8S-001) now carry the ATT&CK T1611 escape technique like K8S-LIVE-007, and live posture no longer reads `runAsUser: false` as UID 0. Both scanners share one set of securityContext checks, and the live pod health checks (K8S-LIVE-001..005) moved next to the other live posture checks with unchanged output. - The MCP `scan` tool's `image` argument builds the same image carrier as `scan --image` and API scans, so its agent and server ids now match theirs (previously the server was named `image:` with an unknown transport and the agent had no `docker://` config path). The image scan also runs off the MCP event loop. Filesystem, OS-package and image-archive carriers come from the same builders on every surface. - Image references with both a tag and a digest (`ghcr.io/org/app:1.2@sha256:…`) are split the same way everywhere: the container image SBOM no longer reads the repository as `app:1.2@sha256` and the digest as the tag, and cloud (AWS, GCP, Kubernetes GPU), `docker run` MCP and Docker Compose packages name the image without its tag. Compose images pinned by digest now carry the full digest as their version instead of its first 12 characters, and `localhost/` is read as a local registry. - Image layer provenance (`created_by` on package occurrences) redacts credentials passed as build args or `ENV` values instead of copying them into reports. - A `--policy` result no longer clears an earlier failed gate (image signature or model provenance policy) in the scan exit code. - Dockerfile rules evaluate whole instructions: continuation lines (including a `# escape=` character) are joined and reported at the first line, and heredoc bodies stay with their `RUN`. A package install, `curl | sh` or `chmod 777` on a continuation line was missed, and cache cleanup on a later continuation line was ignored. `yum`/`dnf`/`microdnf`/`zypper` installs and their `clean` commands and BuildKit cache mounts are recognised. - `DOCKER-002` judges the final build stage: a root builder stage, or `USER root` followed by a non-root `USER`, is no longer flagged; a final stage without `USER` is flagged even when an earlier stage set one (`FROM ` inheritance is followed, `:nonroot` base tags are honoured). `FROM --platform=...`, stage-alias references and `ARG`-defaulted base images no longer produce wrong `DOCKER-001`/`DOCKER-010` findings, and an unresolvable `FROM $VAR` is not guessed. - `DOCKER-003` checks every `KEY=VALUE` pair on an `ENV` line and no longer flags `*_FILE`, absolute-path or `${VAR}` values; `WORKDIR $HOME/app` is not reported as relative. `Dockerfile.md`/`Dockerfile.txt` and other look-alike docs are not parsed as Dockerfiles, and a file without `FROM` gets no findings. - Dockerfile ATT&CK tags match what each rule detects (for example `DOCKER-001` was tagged Escape to Host and `DOCKER-006` Exploit Public-Facing Application); Compose and daemon rules are now tagged. - Findings reachability joins derive each attack path's identifiers once per snapshot index instead of once per finding row. This reduces repeated work during facet aggregation; requests that reach the existing deadline still report partial counts as lower bounds. - The AI BOM (`/v1/agent-bom/manifest`) no longer shows a blank transport for an MCP server whose endpoint sync omitted it: it reports the newest transport any observation of that server recorded, and `unknown` when none did. - `agent-bom iac --format console` lists the findings instead of one count per path: a severity-sorted table of severity, rule id, `file:line` and title, capped at 25 rows with a `+N more finding(s)` line pointing at `-f json` / `-f sarif`, folded to fit 80 columns. `--verbose` lists every finding and `--quiet` omits the table. The per-path and live-cluster summaries count every severity band instead of only critical and high. - SBOM import sets an OS package's distro from its purl, as an image scan does from `/etc/os-release`: the namespace (`pkg:rpm/redhat/…`, `rocky`, `almalinux`, `amzn`, `opensuse`, `pkg:deb/debian/…`, `ubuntu`, `pkg:apk/alpine/…`, `wolfi`) and the `distro` qualifier (`rhel-9.4`, `el9`, `debian-12`, `3.19.1`). RHEL, Rocky, AlmaLinux and openSUSE RPMs from an SBOM now match their distro advisories instead of reporting `rpm-unknown-distro`, and Debian, Ubuntu and Alpine packages match their own release instead of every release. Codename-only releases are left unset rather than guessed. - Explicit options on `image`, `fs`, `sbom`, `iac`, `cloud` and the AI-platform commands now win over the active profile. These commands forward to `scan`, where every forwarded value looked like a default, so a `format = "json"` profile turned `agent-bom image … --format console` into a JSON report file. - NVIDIA GPU driver CVEs on Kubernetes nodes were claimed from a fixed `< 555.52` floor that ignored driver branches (every patched 535/550 LTS driver was flagged), and AMD/Intel driver CVEs from similar floors. Node drivers are now CPE-identified packages matched by the NVIDIA security bulletins (branch-aware fixed versions) and NVD, like drivers found on hosts and images. - `serve --cors-allow-all` no longer sets `AGENT_BOM_CORS_ALL`, which nothing read; CORS is configured from the flag directly. A guard test fails when the runtime writes an `AGENT_BOM_*` variable that nothing reads. - SPDX 2 tag-value export now carries every field of the JSON rendering the grammar can express (`PrimaryPackagePurpose`, `PackageComment`, `PackageHomePage`, summary/description) and writes annotations as spec `Annotator`/`SPDXREF` blocks instead of repeated comment tags, so agent and server context records are no longer read back as software packages. The cloud-inventory extension moved from `DocumentComment` to a document annotation. - A GKE pod's node VM and the GCE inventory or side-scan VM are now one graph node, so an OS CVE on the node disk is an attack path through the pod. - RPM packages from a distro without a supported advisory feed (Amazon Linux, Oracle Linux, SLES, Fedora, Azure Linux, any unrecognised distro, or a supported distro whose release is unknown) were matched against OSV's upstream `Linux` kernel ecosystem, so a distro `kernel` with backported fixes reported upstream CVEs and upstream fix versions. They are no longer matched against any ecosystem; every scan surface instead reports an `advisory_source_unavailable` coverage warning naming the distro release, even for a single package, so the result never reads as clean. The intel package-match API no longer routes `rpm` coordinates to `Linux` either. - Terraform TF-SEC-007 (hardcoded SSH key) and TF-SEC-051 (hardcoded secret) apply to every provider's resources but tagged all of them with `CIS-AWS-1.14`; the CIS AWS control is now attached only to `aws_` resources, and Azure, GCP and other resources carry the provider-neutral NIST controls. - TF-SEC-051 detects Azure's `administrator_login_password`, and TF-SEC-007 detects SSH keys in GCP instance `metadata` `ssh-keys`. - SARIF IaC rules no longer copy the first finding's message, which named one resource, into the rule `fullDescription`, or its compliance IDs into the rule: the rule carries its title and the compliance IDs shared by every result, and each result carries its own `properties.compliance`. - Kubernetes GPU nodes read the full driver version from GPU Feature Discovery's `nvidia.com/cuda.driver-version.full` label instead of a `major.minor` prefix. - Each CVE on a package now carries only its own `ai_risk_context`. The context was extended in place across a package's CVEs, so the Nth CVE repeated the attack summaries of all before it; on `php:8.3.30-cli` that built about 0.9 GB of text for `linux-libc-dev` and dominated JSON export time. - Image rescans distinguish actionable vulnerabilities from incomplete scan coverage. Daemon signature lookup uses a qualified observed repository digest; automated image issues close only with complete successful scan evidence. - Python AST framework discovery labels OpenAI Agents SDK imports and retains LlamaIndex detection. ### Security - `--require-signature`/`--require-image-signature` now needs a cosign public key or a Sigstore signer identity and issuer (`sigstore` extra) (`--cosign-key`, `--image-cosign-key` or `AGENT_BOM_IMAGE_COSIGN_KEY`): without one the gate fails with "a cosign public key is required to enforce signatures", because a signature tag anyone can push proves nothing. A signature that was found but not verified is reported as `present-unverified` (it was `signed`). - Server-side image scans (API scan jobs and the MCP `scan` tool) no longer act on a tenant-supplied reference with the server's own network and credentials: HTTPS only; loopback, private, link-local, CGNAT and cloud-metadata registries are refused (address literals up front, DNS answers at connect time); `~/.docker/config.json`, credential helpers and `AGENT_BOM_REGISTRY_USER`/`PASS` are never used (anonymous pulls only); `AGENT_BOM_REGISTRY_ALLOWLIST` (comma-separated hosts) limits which registries may be contacted; a label-named base image is fetched only from an allowed registry; the Docker daemon is not used unless the operator sets `AGENT_BOM_IMAGE_PULL_MODE=daemon`; and errors no longer carry the upstream HTTP status. The local CLI is unchanged. - In `auto` pull mode a reference without a registry host that exists as a local Docker image is scanned from the local image instead of a same-named (possibly squatted) Docker Hub image. - Registry client: manifest and referrers bodies stop reading at the 8 MB cap instead of being read whole first; a 401 from a redirect host no longer receives the registry's credentials; `sha512` manifest digests are verified and unknown digest algorithms rejected. - Image labels and annotations go through the secret scanner: credentials in them are redacted and reported as findings, and MCP image scan results carry an `untrusted_content_notice`. - Regular expressions in the Dockerfile rules, registry auth-challenge parsing and image config secret scanning no longer backtrack catastrophically on hostile input (a crafted `apt-get` line took 21.8 s at 11 option tokens); a guard test checks every pattern in the IaC, image-evidence and registry modules. - The `ai-enrich` extra excludes litellm 1.107.0, whose wheels were a compromised release (startup-hook credential stealer, 2026-10-21), so installs without the lockfile cannot resolve it. The lockfile already pinned 1.100.1. A guard test fails if any dependency range or the lockfile admits a known-compromised release, and `agent-bom check litellm@1.107.0` reports it as malicious (MAL-2026-2144). - Image scans (`--image`, `--image-tar`, `--k8s`, the MCP `scan` tool, API scans) project as container image nodes keyed by digest instead of agents with MCP servers; earlier node ids are kept as aliases. - The packaged scanner reader role (Helm and `deploy/k8s/rbac.yaml`) grants get/list on workloads, service accounts, role bindings and admission objects so in-cluster inventories are complete; it still grants no Secrets and no mutation verbs. - `-o report.json.gz`, `report.sarif.gz`, `bom.cdx.json.gz` (and `.spdx.json.gz`) write a deterministic gzip stream; `report diff` and `--sbom` read gzip input (SBOM inflation is capped at 10 MiB). CycloneDX, SARIF and SPDX exports now use the JSON report's streaming writer, which encodes each item of a top-level list separately and publishes by atomic replacement, instead of building one string for the whole document. - `GET /v1/scan/{job_id}/result` returns a completed scan's summary and an index of its large sections with item counts, and `GET /v1/scan/{job_id}/result/{section}?offset=&limit=` returns one section, paged when it is a list, redacted exactly as the full result. `GET /v1/scan/{job_id}` is unchanged for existing clients; its redaction and JSON encoding now run in a worker thread, and the Starlette floor is raised to 1.4.1 so responses of 128 KiB or more are gzip-compressed off the event loop. - SBOM import reads CycloneDX XML (1.2-1.7) and SPDX 2.x tag-value in every intake (`scan --sbom`, the API and MCP scan paths, `report diff`). The format is detected from content; both are re-shaped onto the JSON document form and read by the same parser, so each yields exactly the packages, hierarchy, vulnerabilities and cloud-inventory evidence of its JSON twin. XML goes through `defusedxml` with DTDs forbidden (no entity expansion, no external entity or DTD retrieval) and bounded nesting; every import keeps the 10 MiB cap. Previously both were rejected. - Console output groups kernel-header CVEs into one block per image distro release (Debian/Ubuntu `linux-libc-dev` and `linux-headers-*`, RHEL-family `kernel-headers`/`kernel-devel`, SUSE `linux-glibc-devel`/`kernel-*-devel`, Alpine `linux-headers`), with the full severity breakdown; the scan verdict says how many of the CVEs they are. KEV and critical kernel-header CVEs are named on the group line and stay as their own rows, and JSON, SARIF and CycloneDX still carry every CVE. Recognition is scoped to the ecosystem and `os-release` family, so a same-named package elsewhere is never grouped. - The `docker export` fallback of `agent-bom image` scans the exported filesystem with the same bounded walk and extractors as image layers: the `AGENT_BOM_OCI_*` member, size and time limits apply, and a crossed limit is a coverage gap under `docker-export` (a partial scan) rather than an unbounded read. - Image layers emit the canonical purl for scoped npm packages (`pkg:npm/%40scope/name@…`), matching every other scan path. - Pull request CI runs the affected tests instead of the full suite: the changed-domain map plus every test that directly imports, loads or references a changed module, helper, `conftest.py` or fixture (`scripts/pytest_ci_affected.py`), with the contract smoke, in 1–12 duration-sized `Python affected tests (shard N/M)` jobs bounded at 15 minutes. Shared or unmapped inputs no longer start the full 4-shard suite on a PR; the full four-version matrix, full musl suite and four UI E2E shards run after merge and nightly as before. PRs run the musl subset only for dependency/build/workflow inputs and one `UI E2E smoke` job (every packaged route plus accessibility) only when UI sources change. Test jobs report the 50 slowest tests. `docs/operations/CI_RUNBOOK.md` lists the eight required checks and the merge-queue prerequisites. - GPU discovery no longer runs `kubectl exec` into the cluster (`nvidia-smi`, `rocm-smi`, i915 sysfs reads in a pod) when GPU Feature Discovery labels are missing; the driver version stays unknown instead. A guard test fails when any collector builds a mutating or exec-style `kubectl` command (`exec`, `cp`, `apply`, `delete`, `patch`, `create`, …). - Repository scans reject file symlinks across the checkout boundary, enforce clone resource budgets during execution, and bound serverless archive downloads and expansion. Coverage gaps remain explicit. - Credential URI matching in dbt configuration avoids super-linear backtracking on hostile scheme input. - Runtime tool-definition drift includes bounded fingerprints of annotations, output schemas, titles, execution metadata, icons and extension fields; invalid or oversized declarations preserve the previous baseline. - Tenant-scoped disk side-scans require an authorized `client_factory`; the ambient provider-credential fallback is reachable only from the local CLI (`allow_ambient`). API, scheduler and MCP callers already passed the tenant-bound factory. - Daemon-mode image scans on the server apply the server registry policy (allowlist, pinned DNS, no local credential helpers) to signature, referrer and base-image lookups, as registry-mode scans already did. - cosign ECDSA verification selects the digest by curve (P-384 → SHA-384, P-521 → SHA-512), so valid P-384/P-521 signatures are reported `verified` instead of `invalid`. ### Performance - JSON reports (`-o report.json` and `--format json` on stdout) are redacted and encoded section by section instead of building a redacted copy of the whole report and encoding each section in one call. A local 40,000-package offline scan measured 718.5 MiB peak RSS and 77.9 seconds with all 200 seeded advisories retained; streaming output matches the existing encoder byte for byte. - `agent-bom image` on `php:8.3.30-cli` (4,424 findings) peaks at 413 MiB for console and 758 MiB for JSON output instead of about 2.5 GiB, and JSON output uses 52 s instead of 277 s of CPU, with an identical finding set (`docs/perf/image-scan-end-to-end.md`). Text redaction is memoized for the life of one scan (bounded at 8M input characters and cleared when the scan ends), and the inventory snapshot, graph-store compliance stats and typosquat check no longer do quadratic work over large package lists. A 40,000-package offline manifest scan is measured after every merge against a 1,000 MiB peak-RSS budget. - Kubernetes workload graph from live clusters (`scan --k8s`) and manifests/Helm charts (`--iac`, API repository scans): `cluster → namespace → workload → image → package → CVE`, with each workload's service account, its RBAC grants (scope and Secret access) and the Secrets it references. Live pods collapse into their owning controller and images are scanned at the running digest. A new attack-path family follows a vulnerable workload through the service account it runs as to the Secrets and scopes it can reach; a pod with no mounted token never starts one. The report carries a `kubernetes_inventory` section (each container with its image's scan result), the console prints a most-vulnerable-first workload table, and the new read-only `kspm_workload_inventory` MCP tool returns the same inventory. Secrets are never listed. - Read-only admission posture in live KSPM: namespaces running workloads without a `baseline`/`restricted` Pod Security enforce level, audit-only ValidatingAdmissionPolicy bindings, fail-open policies and webhooks, and a cluster with no policy control mechanism (CIS Kubernetes 5.2.1). Manifest rules `K8S-037`/`K8S-038` cover Namespace documents. - Disk side-scan packages and CVEs project onto the VM's own inventory node (EC2 instance, Azure VM, GCE instance) and reach attack paths; `POST /v1/cloud/side-scan` returns per-package/CVE detail and stores it in the tenant graph, and `agent-bom cloud side-scan -f json` and the MCP tool return the same records. A `side_scan_results` report section carries them. - Machine-image side-scan: AWS AMIs (from the AMI's root snapshot, never modified or deleted) and GCE images. Azure managed images are refused with the reason in the CLI, API and MCP. `side-scan-capabilities` states image support per provider and that every side-scan creates and deletes temporary disks. ## [0.110.0] - 2026-10-21 ### Changed - **Outdated local vulnerability data now fails closed.** Applies when nothing is at or above the gate, the local DB is past the age `agent-bom db freshness` warns about (or its freshness can't be trusted), and the run was offline or live OSV did not answer. `check` then exits `2` (incomplete), `scan` exits `1` with a `stale_local_data` issue in `scan_run`, and MCP `check` / `POST /v1/scan/check` return `status: "incomplete"`. Real findings keep their exit codes, and `--exit-zero` does not turn this into a pass. Air-gapped installs that accept old local data pass `--allow-stale-db` or set `AGENT_BOM_ALLOW_STALE_DB=1`. `check` now honours `--require-fresh-db` / `AGENT_BOM_REQUIRE_FRESH_DB` (exit `3`) like `scan`. ### Added - Scoped Supabase project and organization inventory, Vercel project/deployment and team inventory, and Modal/NGC metadata exports. Supabase and Vercel directory graphs retain users and configured roles without inferring effective access; incomplete collection preserves the previous local graph. - Findings queues separate evidence lanes, and scoped HTML impact briefs provide expandable supporting evidence. Installed Python-package metadata can be compared against a retained advisory with scoped remediation receipts; this does not verify a running workload. - Claude Code plugin (`integrations/claude-code`, marketplace at `.claude-plugin/marketplace.json`): bundles the MCP server, pinned to the published PyPI release through `uvx`, plus `/agent-bom:scan`, `/agent-bom:check` and `/agent-bom:fix` skills. `scripts/check_version_alignment.py` keeps the plugin version and the `uvx` pin on the published release. - Exploit story for a CVE occurrence: `GET /v1/graph/exploit-story` and the MCP `finding_detail` `exploit_story` block say what the vulnerable package puts at risk (agents, MCP servers, tools, credential names, data stores, cloud resources and identities, each with its hop-by-hop path and evidence tier) and how it could be exploited (decoded CVSS 3.x/4.0 vector, CWE attacker capability, KEV, EPSS, reachability, fix), with a narrative built only from recorded fields. The finding drawer and the investigation path show it, and the path canvas can draw the at-risk hops past the package. ### Fixed - Graph and finding identities retain repository, account, tenant and occurrence boundaries; current-estate reads preserve snapshot scope and relationship selection. Shared image inventory remains distinct from workload instances, and configured identity scope does not imply tool access. - The terminal demo recording keeps complete finding rows when the current table exceeds its viewport and waits for the first scene before recording. Refreshed product screenshots and the recording from current source, corrected directory collection guidance, and moved the Claude Code plugin entry out of the already-published v0.109.0 history. - `agent-bom check` no longer reports results from an outdated local vulnerability DB as complete. Whenever `agent-bom db freshness` would warn (past the configured max age or the 7-day danger age), online checks also query OSV live and merge by advisory ID and alias. Previously a 7-day danger age above a raised `AGENT_BOM_VULN_DB_MAX_AGE_HOURS` skipped OSV and missed newer CVEs. Offline checks and failed live lookups say plainly that results may be incomplete and how old the local data is, and local hits from outdated data no longer print a check mark. CLI JSON, MCP `check` and `POST /v1/scan/check` add `vuln_data_freshness` and `completeness`, and the MCP `scan` summary now includes `vuln_data_freshness`. - Vulnerability-data freshness fails closed. A local DB written by a newer agent-bom schema, or one whose sync metadata cannot be read, is no longer treated as fresh: `db freshness` warns, `check` also queries OSV live, and offline results are marked incomplete. `vuln_data_freshness.integrity_issue` names the problem. A freshness probe that errors now counts as outdated instead of failing the check. - `check` on an outdated local DB reports `complete` only when OSV actually answered for the package in that run (a completed OSV batch or a response-cache hit). Before, it was inferred from the absence of errors. When OSV did not answer, the result is `incomplete` with "live OSV did not answer for this package". - Advisory merging no longer folds distinct advisories into one finding through a shared alias. A local DB that kept a stale upstream alias group (for example CVE-2021-23337/GHSA-35jh fused with CVE-2026-4800/GHSA-r5fr) made `check` report 3 lodash@4.17.20 findings instead of 5, and showed CVE-2021-23337 as fixed in 4.18.0. Now a cluster never holds two different primary CVEs, a record's own CVE id outranks a CVE alias, and a stored record whose aliases name several CVEs is matched by its own ID only, with a warning to run `agent-bom db update`. Live OSV alias sets reconnect each advisory to its GHSA, and every finding keeps its own fix version. - EPSS and KEV from the local vulnerability DB no longer cross a stale fused alias group. A `CVE-…` row takes only its own scores. Other rows take a single CVE alias, plus their upstream CVEs as before. A row whose aliases name several CVEs takes none, so CVE-2021-23337 no longer inherits CVE-2026-4800's EPSS or KEV. - A merged finding keeps the fix version of an alias record when the record chosen for severity has none. For example, a local CVE-2020-28500 row with no fix merged with the live GHSA-29mw-wpgm-hmr9 record now reports `fixed_version` 4.17.21 instead of none. The fix only ever comes from a record for the same package. For Debian, Alpine and RPM packages an empty fix still means no fix for that release. - `GET /v1/graph/node/{node_id}` and `/v1/graph/node/{node_id}/neighbors` accept node ids that contain `/` (cloud resource ARNs, file paths, scoped packages), raw or `%2F`-encoded, instead of returning 404. - `GraphRollupResponse.collapsed` is typed as a list of rows in the OpenAPI contract and the generated UI types, matching what the attack-path roll-up returns. - CVEs found on VMs roll up under their instance instead of appearing as graph orphans, carry their occurrence verdict and effective reach on the advisory node, and no longer count their own instance as a source that reaches them. - MCP `blast_radius` reads its holders from the same graph walk as `GET /v1/graph/impact` (a `holders` block, with per-row servers and agents taken from it) and returns each row's derived `reachability`, so MCP and REST no longer report different holders for one advisory. - Findings, the `reachability` filter and facets, attack paths and MCP read one reachability verdict derived from the stamped graph evidence, so a finding reached by a provenance-backed path reads `likely` (never `confirmed` without function-level or runtime evidence) and `?reachability=reachable` returns only `likely`/`confirmed` rows. - `GET /v1/findings` cursor pages report the same exact `total` as the first page (`total_kind: exact`) instead of `null`/`unknown`; a cold count cache runs one COUNT, approximate reads still skip it, and scope-filtered walks keep the honest marker. - The MCP `context_graph` tool builds from the tenant's persisted scan snapshot (or `scan_id`) by default and labels its `source` and `scope`; live discovery of the MCP host's own agent configurations runs only with `live=true` or a `config_path`. - One count per metric across pages. An issue's severity is now its worst open occurrence, so the findings page (sorted by reach) and the overview no longer disagree by one high or medium issue. An explicit `CVE` finding reported by a cloud source is classified as a vulnerability, so the overview's open-CVE tile matches the posture dimension. KEV is counted in issues beside the issue tiles and in the exec summary (`issues.kev`; occurrences remain in `finding_counts.kev`). Remediation reads the findings default window and returns it as `window`. - Units and scopes are named wherever two numbers could be read as one: overview security areas say "occurrences", the agents page says "Agents on this host" with the estate count beside it and counts unique credentials, the posture dimension says "vulnerability occurrences", the compliance page counts control frameworks and risk mappings with the overview's definition, and the NIST SP 800-53 panel leads with the framework list's pass/fail and labels the catalog rescoring as a separate basis. - Agent and server names come from one resolver: a recorded display name, otherwise one canonical formatting of the identifier; exposure paths no longer append "service" or "connector". - Native trace imports expose bounded provider retry timing while retaining the last committed checkpoint on failure. - Bulk findings require a JSON boolean for absent-finding reconciliation; invalid CVSS errors omit submitted values. - JSON file exports publish through atomic replacement so encoding or write failures preserve an existing report. - Credential binding projection retains only referenced identity IDs, preserving ambiguous matches without loading the entire store-backed graph into memory. - The main CI regression tracker reconciles on cancelled head runs, ignores non-decisive runs, and closes with one comment citing the green run instead of overwriting the failure evidence. - Distribution freshness reports provider-side verification gaps in the job summary and no longer opens or reopens the drift issue for them; stale, unreachable and unmonitored surfaces still alert. ## [0.109.0] - 2026-10-15 ### Changed - Trace pull, trace collection and trace findings (Langfuse, LangSmith, OTel) are experimental and **off by default**. Enable them with `AGENT_BOM_EXPERIMENTAL=traces`. While disabled, `GET /v1/traces/connectors`, `POST /v1/traces/connectors/{provider}/pull`, the trace collection routes and `POST /v1/traces/attack-paths` return `404` with the enable hint; `POST /v1/traces` still accepts OTLP for runtime and cost telemetry but records no trace findings; graph snapshots do not overlay trace events or emit `SHADOW_AI` trace findings; the MCP `runtime_correlate` tool returns the hint for `otel_trace`; and the dashboard labels Platform traces *Experimental* and shows the hint instead of the pull form. Cortex agent coverage is unchanged. ### Added - One experimental-feature registry (`agent_bom.core.experimental`) lists every experimental feature with its surfaces, how it is enabled and its doc. `docs/EXPERIMENTAL.md` is generated from it (`scripts/generate_experimental_docs.py --check` runs in CI and `make preflight`), storage tiers read their experimental backends from it, `agent-bom doctor` prints an Experimental features section (and `experimental` in agent-mode JSON), and `GET /v1/system/health` reports `experimental_features` with live enablement. - `HOSTED_ON` (workload → host, a dependency relationship) records where an agent, MCP server or container runs. A cloud-hosted agent is hosted on its cloud resource (the account and provider `HOSTS` rollup is unchanged), and a Kubernetes-discovered MCP server is hosted on its pod and the pod on the node VM named by the node's provider id (AWS, Azure, GCE); discovery records the pod uid, namespace, node and provider id. Component paths walk these edges, so a CVE on a VM reaches the agent whose server runs on it, and a compute instance with a CVE and nothing hosted gets its own path. Graph exports map the edge to `HOSTED_ON`. - One graph node per real-world asset across sources. Observations that share a strong provider-native key (qualified ARN, AWS instance id with account and region, Azure ARM id case-insensitively, GCP self link, Kubernetes uid, image digest, principal id, Snowflake account-qualified name) merge onto a deterministic canonical id derived from that key, before attack-path analysis and again after finding rows name new assets. The merged node records `attributes.identity` (canonical key, basis, replaced ids, one observation per source node and data source, conflicting fields) and the union of data sources; conflicting strong keys never merge and are counted. Host names, private addresses, MAC addresses and names within an account never merge: they add a non-traversable `POSSIBLY_CORRELATES_WITH` candidate with matched signals, confidence and sources, suppressed when both sides carry distinct native ids. CloudTrail principals are typed from the recorded caller identity (an assumed-role session is the role). Snapshot correlation joins on the same keys (`scoped-identity.v5`). Replaced ids persist in the tenant-scoped `graph_node_aliases` table (SQLite, and Postgres with forced row-level security via Alembic `20261014_01`); imported-trace inventory bindings resolve through it. The demo estate adds a compute lane of 12 VMs seen by inventory, CloudTrail, a side scan and a posture finding, plus 3 host-name-only sensor findings that stay separate candidates. - Agents and MCP servers get one graph id from shared helpers in every producer (graph builder, export graph, exposure paths, demo estate). A remote MCP server is one node per tenant, a launched server with arguments one node per host, and a name-only server stays under its agent; shared server nodes list every declaring agent, and a credential slot is reachable only from the agents that configured it. Exposure-path hops, tools and credentials in JSON and SARIF are graph node ids with a `nodeLabels` map for display. Runtime incidents bind to one agent by graph id or source scope plus name; an ambiguous bare name binds to none and is counted in the `runtime_incident_feedback` analysis status. - `GET /v1/graph/diff` is bounded: the default `view=summary` returns counts per change kind by entity type and relationship plus the most significant changes (new critical findings, new credential reach, removed controls, new attack paths) and compares the latest two snapshots when no IDs are given; `view=detail` pages change rows with filters and a cursor; `view=full` keeps the legacy lists under a row and byte cap with `truncated`/`complete` flags and omits node attribute blobs. On the showcase estate the default answer drops from about 8 MB to under 16 KB. The new read-only MCP tool `graph_diff` answers from the same function (94 tools). - Imported Langfuse, LangSmith and OTLP JSON traces normalize into one canonical metadata-only event and become `runtime_observed` graph edges aggregated per source, relationship and target, bound only by exact inventory or canonical IDs. Attack-path ranking and credential reach read them; unmatched and name-only spans are counted in the `runtime_trace_projection` analysis status. Screened trace signals, vulnerable tool calls and unlisted agents or tools become unified findings, including the new `SHADOW_AI` finding type. Langfuse pulls now request model and usage fields and LangSmith pulls token and cost columns. - Graph relationship inspectors and recorded rows surface receipt evidence types and source observation times separately from graph-record timestamps and traversal eligibility. Missing and mixed evidence stay explicit. - Graph relationship details and recorded-link rows explain agent/server use, available tools, dependencies and findings in plain language. Recorded source, basis and package fields remain separate from relationship meaning; conservative tool-impact mappings and missing source receipts stay explicit. - Public first-run and investigation feedback forms capture setup friction and decision context. Inaccurate-finding reports now capture directed graph identity, scope, provenance, freshness and incomplete evidence, with contribution and support routing through the active repository. - Published-package first-run verification checks the offline report, persisted sample snapshot and rendered graph on Linux/macOS, with desktop/mobile light/dark captures, separate timings and retained failure receipts. - A shorter release-focused README leads from a repository scan to the persisted sample graph, explains the server handoff, and links the full source-version product tour. - Add opt-in snapshot finding reads with per-read differential verification and fallback to current findings on mismatch or unavailable snapshots. Qualification preserves live enrichment and retention semantics; optimized metadata-only reads remain deferred. - Opt-in scan finding snapshots persist completed job evidence in tenant-scoped memory, SQLite or PostgreSQL stores. Backfill and purge commands manage retained jobs; deletion and expiry remove snapshots even after writes are disabled. Reads require the independent, default-off qualification flag. - Direct compromise assessment is available through the authenticated graph API, `graph-paths compromise`, the graph-profile MCP tool, and the graph entity drawer. Requests require explicit assumptions and return a pinned snapshot revision with action-scoped historical permission receipts, denials, and unknowns. Partial storage reads fail closed; this does not establish current access, successful execution, or multi-hop compromise. - Storage backends now carry a declared support tier: PostgreSQL (server system of record) and SQLite (local, CLI and pilot) are supported, ClickHouse is an analytics sink only, and the Snowflake control-plane stores and the Neptune graph backend are experimental. When an experimental backend is selected, the API logs one warning at startup that names the backend, its tier and `docs/STORAGE_BACKENDS.md`. In a deployment that looks multi-tenant, the warning states that tenant isolation for that backend is not proven. Startup continues by default. `AGENT_BOM_REQUIRE_SUPPORTED_STORAGE=1` refuses to start with an experimental backend. `agent-bom doctor` lists the tier of each selected store under Platform integrations; experimental rows count as warnings. - `--external-scan`, `findings push` and the MCP `ingest_external_scan` tool now import Prowler v4/v5 JSON-OCSF and AWS Security Hub ASFF reports. FAIL and MANUAL Prowler results and active Security Hub findings become cloud posture findings with account, region, resource ARN, vendor compliance references and tool provenance; Security Hub vulnerability records become CVE findings. PASS, muted, archived, suppressed and resolved records are skipped and counted in a scan notice. Imports are file-based: no credentials, network access or tool execution. - `docs/VENDOR_COVERAGE.md` and `docs/VENDOR_COVERAGE.json` give a generated provider × capability matrix (connect, API connection, scheduling, discovery, inventory, benchmark posture, identity, data, side-scan, change events, runtime evidence), integrations by category, and a list of provider lists that disagree. Each cell cites its source constant. `scripts/generate_vendor_coverage.py --check` runs in `make preflight`. - Scanner importer contract (`agent_bom.parsers.importers`) with a published transparency manifest per importer and an opt-in `agent_bom.importers` entry-point group for third-party importers. See `docs/IMPORTERS.md`. - A Python direct compromise assessment contract classifies scoped authorization receipts from a selected graph node or an explicitly assumed affected component. It preserves action-specific denials, uncertainty, original edge direction and collection timestamps. This read-only foundation does not establish current access, successful exploitation or multi-hop reachability. ### Changed - An operator-supplied VEX document (`--vex`, or the API scan request `vex` field) now suppresses findings it marks `not_affected` or `fixed` for a matching vulnerability and product: they stay visible with the VEX justification but leave totals, risk scores, SARIF active results and exit-code gates. Findings record `vex_source` (`operator` or `discovered`); VEX discovered inside scanned artifacts remains evidence only, and `under_investigation`/`affected` never suppress. VEX statements that name products now apply only to those packages. - Browser-extension findings use the `BROWSER_EXT` finding type and source in JSON output instead of the non-enum `BROWSER_EXTENSION_RISK` / `BROWSER_EXTENSION_SCAN` values; stored rows with the old values still load as `BROWSER_EXT`. - Cloud discovery for AWS (AI services, organizations, inventory), Azure, GCP (inventory and authorization), Snowflake, Databricks, CoreWeave, Nebius, Lambda Labs, RunPod, local GPU infrastructure and the NVIDIA advisory check is split into named stages. Each stage keeps its own error isolation and warning text, so discovery output, warnings and API calls are unchanged. Kubernetes GPU parsing shared by CoreWeave and Nebius moves to `cloud/k8s_gpu_common.py`; GCP authorization record normalizers move to `cloud/gcp_authorization_records.py`; Snowflake notebook discovery moves to `cloud/snowflake_notebooks.py`. 35 architecture debt entries are retired. - Managed-node EKS bootstrap no longer requests an unused Auto Mode policy or a standalone cluster-encryption policy. Encryption permissions remain scoped to the cluster's KMS key through an inline role policy; the cluster-first bootstrap command includes that policy. - The top-level module guard (`scripts/check_package_layout.py`) now names a likely subpackage for each new `src/agent_bom/*.py` file and points to the new `docs/CODE_MAP.md`, which maps common changes to their owning packages, canonical models and layering rules. The guard has its own regression test. - `CONTRIBUTING.md` adds a "first PR in 30 minutes" path, good first contribution areas and maintainer response expectations. A maintainer-facing `Good First Issue` template is added. - The deployment overview classifies each `deploy/` target as Supported, Preview, Reference or Community. No deployment files changed. - `--external-scan` reports are now read with the shared parser size limit (`AGENT_BOM_MAX_MANIFEST_BYTES`) in the CLI and API scan paths. - The scan API route module is split into focused modules with no change to routes or responses: the local-path scan jail (`api/scan_path_jail.py`), AI-scan execution (`api/ai_scan_runtime.py`), bulk-ingest request models (`api/bulk_findings_ingest.py`), finding row identity and legacy row builders (`api/finding_row_shapes.py`), job response payloads (`api/scan_job_views.py`), correlation cohort ids (`api/scan_cohorts.py`) and findings list helpers (`api/finding_list_helpers.py`). The dedicated AI-asset scan endpoints (`/v1/scan/dataset-cards`, `training-pipelines`, `browser-extensions`, `model-provenance`, `prompt-scan`, `model-files`) move to `api/routes/ai_scans.py`. Existing imports from `agent_bom.api.routes.scan` keep working. - The `/v1/findings` read path is decomposed into named stages with no change to responses: query validation, the scan-findings half, page strategy (scoped keyset, merged scan + hub keyset, hub-only, in-memory), facets and envelope assembly. The view-filter and issue-grouping handlers, the bounded facet walk and the scan + hub merge walk get the same treatment. A read that pages through many rows (view filters, issue grouping) now folds, filters and sorts the scan-findings half once per read instead of once per internal page. - The largest scanner engines are decomposed into named stages with no change to results: package vulnerability scanning (`scan_packages`), the cloned repository tree scan, the MCP `scan` tool body and the live Kubernetes posture scan. Each now reads as a short orchestrator over input preparation, version resolution, advisory lookups, enrichment and result assembly. ### Fixed - Alias merging no longer lets a namespace-default `medium` (an advisory with no score or rating, such as a PYSEC record) outrank a rated alias: CVE-2024-12797 in `cryptography` now takes the GHSA `low` rating. Console and HTML severity badges show "(unscored)" when the band is only that default. - Whole-queue path searches (the `should_i_deploy` gate and filtered `exposure_paths`, including `/v1/graph/exposure-paths`) read every stored path instead of the first rank window while reporting a complete search; beyond the search cap the answer is a labelled lower bound and the gate never allows. `/v1/graph/attack-paths` marks totals beyond the rank window as lower bounds. The deploy gate rechecks the pinned snapshot generation and returns a retryable error when it changed mid-read. - `AGENT_BOM_GRAPH_CONTRACT=enforce` no longer reports a clean contract after dropping edges: the snapshot's `relationship_contract` analysis records `rejected` counts per relationship and entity pair with a bounded sample of edge ids. - Graph analysis limits are reported only when they hide something. Credential reach no longer marks a scan `limited` (and therefore `partial`) when a depth-bounded route only leads to a credential already reached by a shorter route. A path budget keeps any earlier agent-budget reason instead of replacing it. The current-estate view now carries the worst analysis status of its source scans, so a limited source is no longer shown as clean. - Compliance control tags stay consistent across findings, the graph and exports. Toxic-combination findings no longer put OWASP Web Top 10 IDs (`A06:2021`, `A01:2021`) or `LLM06:2025` into the OWASP LLM field; they now carry catalog-backed NIST SP 800-53, SOC 2 and (for agents reaching privileged tools) OWASP LLM `LLM06` / Agentic `ASI03` controls, which survive report rehydration. Graph vulnerability nodes keep NIST 800-53, FedRAMP, CMMC and PCI DSS tags. CWE lookups are case-insensitive in every tagger. Framework-qualified export tags no longer treat a colon inside a control ID as a framework prefix. A dead SAST CWE-to-CMMC lookup that could never resolve was removed. - Compliance controls are no longer passed or failed on evidence that never ran. "Scan for vulnerabilities" and "component inventory" controls (NIST RA-5 / CM-8, FedRAMP RA-5 / CM-8, CMMC `RA.L2-3.11.2`, CIS `CIS-02.1` / `CIS-07.1` / `CIS-07.5`, SOC 2 `CC7.1`, NIST CSF `ID.RA-01` / `ID.RA-02` / `DE.CM-09`) pass only on a scan whose inventory or vulnerability lane actually ran, scored from that lane's latest scan. IaC-only, browser-only, secrets-only, cloud-benchmark-only and `--no-scan` runs now read `not_assessed` (reason `detective_evidence_not_collected`) instead of `pass`, and a partial vulnerability lane reads `not_assessed` (reason `vulnerability_coverage_incomplete`). `--no-scan` records a `vulnerability_scan_skipped` receipt in `scan_run`. NIST 800-53 catalog controls are evaluated only by a finding's own evidencing checks, so SR-3 and SI-4 no longer fail on every CVE. CMMC no longer tags `RA.L2-3.11.2` or `CM.L2-3.4.3` onto CVEs. - ISO/IEC 27001 findings reached through NIST's SP 800-53 crosswalk (for example `A.5.17` and `A.5.16` on committed credentials) were tagged but missing from the ISO catalog, so `/v1/compliance` and the evidence export dropped them. The bundled ISO catalog now lists all 25 Annex A controls a tagger can emit, by identifier with agent-bom's own short descriptors. A test enumerates every tagger and fails on any emitted ID its framework's catalog does not contain. - `/v1/compliance` and the evidence export scored MITRE ATT&CK against the bundled catalog, while the taggers and CLI narrative used the active (synced) catalog. All surfaces now use one resolver, so a technique that exists only in a synced catalog appears everywhere. The documented technique count still comes from the bundled catalog. - A finding's `applicable_frameworks` now always includes every framework it carries a control tag for, in addition to the frameworks the source/asset/finding-type selection table assigns. Hub posture counts by `applicable_frameworks` and `/v1/compliance` counts by tags, so the hub no longer omits a finding that `/v1/compliance` counts. This now includes graph toxic-combination findings, which were tagged after classification, and survives report rehydration. - `/v1/findings?framework=X` now matches a scan finding only when it carries an X control code that exists in X's scoring catalog, the same rule `/v1/compliance/X` counts by. An IaC rule declaring an 800-53 control outside the bundled catalog (for example `CP-9`) no longer lists its finding under NIST 800-53 while the NIST line counts nothing; the exact `control=` drill is unchanged. Falling back to `applicable_frameworks` listed every SBOM CVE under PCI DSS while the PCI DSS line counted none. Bulk-ingested findings, which carry only the producer's applicability, still match on it. - IaC findings now carry the NIST SP 800-53 controls their rule declares (for example `AC-3`, `AU-2`) in `nist_800_53_tags`, and the FedRAMP Moderate subset in `fedramp_tags`, so the NIST 800-53 and FedRAMP lines count them. Only controls in the bundled catalog are tagged, and detective controls (RA-5, CM-8) never are. CIS AWS Foundations Benchmark IDs are not CIS Controls v8 safeguards and stay out of `cis_tags`. - The CIS Foundations Benchmark scorecard line no longer counts Databricks security checks, which are vendor best practice (Databricks publishes no CIS benchmark). They remain listed by `/v1/cis/checks`. ### Security - API local-path scans: a set-but-blank `AGENT_BOM_API_LOCAL_PATH_SCANS` no longer enables local filesystem scans. A blank value is treated as unset and falls through to `AGENT_BOM_ENABLE_LOCAL_PATH_SCANS`, then to the disabled default. ## [0.108.4] - 2026-10-09 ### Fixed - `doctor` warns when its selected OSV scan cache is unreadable, locked or incompatible instead of reporting it as healthy. Diagnostics reuse the scanner path resolver, open the cache read-only with a bounded lock wait, and give a repair/recheck hint without exposing paths or exceptions. - Align documentation-site links, package metadata and Action examples with the transferred repository; accept release signatures from its current and historical owners while rejecting unrelated workflows. - Managed PostgreSQL initialization validates existing maintenance-role attributes without reapplying superuser-only flags. Unsafe existing roles fail initialization; pre-provisioned safe roles remain usable on RDS. - ClickHouse analytics now creates its database before selecting it for HTTP queries. Connecting to a fresh server no longer fails with `UNKNOWN_DATABASE`; bootstrap retains credentials and stops on authorization errors. - Corrected the ClickHouse benchmark example to use an HTTP endpoint and the registered `report analytics` command. Deployment guidance now explains optional ClickHouse analytics alongside PostgreSQL/SQLite and the bounded analytics queue's durability limits. - Helm API shared-state safeguards now account for autoscaler maxima and KEDA fallback replicas, including deployments starting at one replica. API/UI disruption budgets cover configured scale-out, and extra API environment entries cannot override the chart-derived replica safety setting. Deployment guidance distinguishes single-replica SQLite, shared-state PostgreSQL API scaling, and single-writer gateways. PostgreSQL table partitioning is not automatic database sharding; live load, failover, and HA need qualification in the target deployment. - Label CIS benchmark checks separately from cloud inventory in scan pipelines; preserve unknown check outcomes and explain target-dependent scan scope. - `serve --demo-estate` and `api --demo-estate` now keep demo scan jobs in the same SQLite file as the demo graph (`/control-plane.db`) unless `--persist` or another backend is configured. A restart no longer shows the 6,803-node graph next to zero jobs and re-runs the curated scan; jobs are available on the first response. Existing demo installs reseed once after upgrading. - `/v1/overview`, and `/v1/posture` when it has no data yet, report `demo_estate_seeding` while the startup seed runs, and the dashboard shows a seeding status instead of the first-scan guide. - The spend forecast no longer turns minutes of history into a daily burn rate. On the demo estate, $6,851 recorded over about 50 minutes had shown $356,507.91/day and an $8,236,481.61 projected period. A burn rate now needs at least 6 hours of recorded calls, and `history_span_hours` reports how much history there is. AI Spend explains the gap, shows large amounts compactly ($8.24M) and no longer overflows its forecast cards. - The Scan Jobs pipeline no longer shows more critical findings than total findings ("30 findings · 103 critical"). Both counts now come from the unified finding summary. Older summaries show a critical count only when it is no larger than the total. Jobs without stage events hide the stage-timing rows and the zero wall clock instead of listing "Unavailable" for every stage. - On the demo estate, the sidebar no longer links Cloud Governance and Control Plane Security, because the backend does not serve them there. The UI now points to `agent-bom serve` (or `serve --no-ui` for the API only) instead of the retired `agent-bom api` command. - The Agent Activity header now counts the stream events listed below it, with the runtime events for the window counted separately. Before, it said "0 events across the last 30 days" above a populated stream. The stream header and event details still say when the producer is unknown, but rows no longer repeat it. - Inventory now shows an error with a Retry button when a request fails (including 429 rate limits), instead of staying on its loading skeleton. - The AI BOM counts packages, cloud assets and findings from the same inventory summary that Inventory uses, instead of showing "Not collected". - KPI strip labels and hints now wrap instead of being cut off, and finding rows show readable detection labels ("Cloud security", "CIS fail") instead of raw enums. - Credential patterns no longer fire inside ordinary identifiers. The OpenAI key pattern matched the `sk-` in `task-`, `risk-` and `disk-`, so CSS class names and schema ids such as `risk-campaign-evidence-label` became CRITICAL "OpenAI API Key" findings. Vendor-prefixed patterns (OpenAI, Anthropic, AWS, GitHub, GitLab, Slack, Stripe, Google, Twilio, SendGrid, Mailgun, Square, npm, PyPI, Discord, Telegram, JWT, Shopify, Databricks) now require a token boundary before the prefix. An OpenAI key body must also contain a digit and must not be a lowercase hyphenated slug, and `sk-ant-` keys report as Anthropic only. A `postgresql://${USER:-default}@host` shell default is no longer read as a password. On this repository, `agent-bom secrets .` drops from 39 to 12 credential findings (OpenAI 26 to 1, connection strings 8 to 6). Real-format `sk-...` and `sk-proj-...` keys are still detected, and pattern cost on a 200 KB response is unchanged. - Distro fix advisories (Debian `DLA-`/`DSA-`, Ubuntu `USN-`, AlmaLinux `ALSA-`, Red Hat `RHSA-` and similar) no longer report `unknown` severity when their upstream CVEs are scored. Such an advisory takes the highest CVSS score, or else the worst label, of the CVEs it fixes. The scores come from records already in the scan and from the local vulnerability DB, with no extra network request. `severity_source` names the CVE (`upstream_cve:CVE-…`), and EPSS and KEV attach through the same CVEs. The advisory id is no longer projected into `cve_ids`. An advisory with no scored upstream CVE stays `unknown` and still fails the severity gate closed; the exit-code reference now documents this. - The "SQL query is built through string interpolation" rule honors `# nosec`, `# nosec B608` and `# noqa: S608` anywhere on the call or on the assignment that built the query. It no longer flags queries whose interpolated values are only bind placeholders (`?`, `%s`, a separator `join` of them) or module-level UPPER_CASE constants the function does not rebind. A `# nosec` naming another rule, or any interpolated parameter, is still reported. On this repository, `agent-bom scan -p .` drops from 202 to 29 such findings. - CPython runtime findings now carry `fixed_version` when OSV publishes release-numbered fix windows (for example `3.9.24`). Only the window that contains the installed release supplies a fix, so no cross-branch upgrade is suggested. - The console summary, Agents table, dependency tree, HTML agent cards and graph summary now count only real MCP servers. A plain repository scan no longer shows "0 servers" in the summary and "Servers 1" in the Agents table. - Project scan auto-detect no longer stops at 4,000 files per probe. A capped probe both missed notebooks, Terraform and IaC deeper in a normal-sized repository and recorded a `discovery_file_limit` coverage gap that marked the whole scan `partial`. - Compliance framework mappings were corrected, so **control tags differ from those in earlier reports**. Re-scan before comparing history, because stored findings keep the tags they were written with. Changes by framework: - **OWASP LLM Top 10**: every ID now uses the 2025 numbering. Before, 2023 and 2025 IDs were mixed. Vulnerable packages are now LLM03 Supply Chain (was LLM05). Exposed credentials and readable data are LLM02 Sensitive Information Disclosure (was LLM06 or LLM07). Exec tools and injection CWEs are LLM05 Improper Output Handling (was LLM02). Excessive agency is LLM06 (was LLM08). Training-data packages are LLM04 Data and Model Poisoning (was LLM03 and LLM04). LLM08 Vector and Embedding Weaknesses now fires for vector-store packages. A CVE in an AI framework alone is no longer tagged poisoning. CWE-287, CWE-444, CWE-639 and CWE-942 no longer map to an OWASP LLM risk. - **EU AI Act**: Articles 5 (prohibited practices) and 6 (high-risk classification) are no longer tagged and are removed from the catalog. Neither can be inferred from dependencies or tools. Article 10 is evidenced only by dataset findings. New tags are Article 14 (human oversight) for exec-capable tools and Article 12 (record-keeping) for logging weaknesses. Tags express technical relevance, not a legal classification. - **SOC 2**: CC7.1 is now labeled as vulnerability and configuration-change detection. It is evidenced by a fresh scan instead of failing on every CVE. CC7.2 (anomaly monitoring) is no longer tagged from dependency CVEs. CC6.8 (malicious software) now requires a known-malicious package instead of any HIGH+ CVE. - **NIST AI RMF**: subcategory IDs now match their AI RMF 1.0 meaning. Third-party and supply-chain risk is GOVERN 6.1 / MAP 4.1 (was GOVERN 1.7 / MAP 3.5). Human oversight is MAP 3.5. Impact is MAP 5.1. Security evaluation is MEASURE 2.7 (was MEASURE 2.5). Risk response is MANAGE 1.3 (was MEASURE 2.9). The MAP 1.6, MANAGE 2.2 and MANAGE 2.4 rules were dropped because no subcategory with that meaning fits them. - **CIS Controls v8**: library allowlisting is CIS 2.6 (was 2.7) and hardening templates are CIS 16.7 (was 16.11). - **NIST CSF 2.0**: containment is RS.MI-01 (was RS.MI-02), and the DE.CM-09 title now matches CSF 2.0. - **OWASP Agentic Top 10**: ASI01, ASI08 and ASI10 now carry their 2026 titles. ASI01 (Agent Goal Hijack) and ASI09 (Human-Agent Trust Exploitation) are no longer applied to every dependency CVE. ### Performance - The retained-findings fold computes each job's scope key once instead of three times per finding. A cold `/v1/posture` on the demo estate drops from 17.5M to 7.6M function calls (38.2 s to 25.7 s under cProfile on a loaded host). - `agent-bom scan -p .` on this repository uses 33-39% less CPU (140-141 s to 86-95 s user CPU over two runs each, peak RSS 335-395 MB to 307-325 MB) with identical findings (941) and packages. The AI component scanner skips any regex whose required literal text is absent from a file (66 to 20 CPU-seconds for that pass, same 601 components); AST source selection walks the project once instead of once per language; project auto-detect walks it once instead of once per surface; and Python entrypoint discovery walks each module once instead of three times. - `agent-bom --version` answers without loading the command tree: 1.2-1.7 s down to under 0.15 s. Every other command also imports less at startup (output formatters, the MITRE catalog fetcher, the warehouse graph builder and fleet API models now load on first use). - Dashboard page loads no longer freeze the API. Page reads already ran on worker threads, but about ten CPU-bound aggregate reads at once (overview, findings, compliance, posture counts, graph) left the event-loop thread waiting on the GIL. `/health` and `/_next/static` chunks queued behind them for tens of seconds. Those reads now compute two at a time (`AGENT_BOM_HEAVY_READ_CONCURRENCY`, default 2). Waiters beyond the worker-thread ceiling get 429 instead of an unbounded queue. Concurrent reads of the same job payload share one parse instead of each parsing it. Hashed `/_next/static` assets are served from memory without worker-thread hops and marked `immutable`, and the schedule poll moved off the event loop. On `serve --demo-estate` with SQLite, after seeding settles, firing ten page reads at once with static and `/health` probes running alongside: max event-loop stall drops from 31.7 s to 2.6 s, max static-asset latency from 38.0 s to 4.6 s and max `/health` latency from 37.9 s to 2.9 s. Cold page reads drop from 35-96 s to 7-17 s, and warm ones from 19-35 s to 4-12 s. Measured on a 10-core dev host at load average ~35, so absolute numbers are high. ### Changed - Project scans no longer stop the secret scan at 1,000 files or AST analysis at 500 source files. The budgets are now 10,000 and 5,000, so `agent-bom scan -p .` on this repository covers all 2,634 secret-scan files and all 1,804 AST source files instead of reporting both as coverage gaps. Findings rise from 739 to 862 (secret/PII 26 to 119, SAST 31 to 61). Full coverage costs more: user CPU goes from 97-105 s to 205-266 s over two runs each, peak RSS from 433-552 MB to 1.17-1.46 GB, and the JSON report from 39 MB to 95 MB. Most of the extra CPU comes from AST analysis running twice per scan (agent prompt discovery and source analysis each call it). The scan outcome on this repository is still `partial` for reasons these budgets do not cover: 12 TypeScript files the bundled tree-sitter grammar cannot fully parse, 7 CloudFormation templates with unresolved values, and 7 packages with unresolved versions. - The gateway `/mcp/{server}` relay now runs as an ordered pipeline of named, typed stages (request admission, identity, runtime profile, edge/spend/fleet admission, layered tool policy, forward) that pass explicit request state instead of sharing one 1,464-line closure. Status codes, response bodies, headers, audit records and metrics are unchanged. ### Security - The REST API now validates the `Host` header before routing or authentication. A loopback `agent-bom serve` / `agent-bom api` answers only loopback host names, so a web page can no longer reach a local control plane through DNS rebinding and obtain the zero-config dashboard session. Non-loopback deployments can restrict accepted host names with the new `AGENT_BOM_API_ALLOWED_HOSTS`. Without it they keep accepting any Host and log a startup warning. Malformed configured host entries fail startup instead of silently disabling the allowlist. - Cookie-authenticated state-changing requests now also require a trusted `Origin` (or `Sec-Fetch-Site: same-origin`). API-key and bearer clients are unaffected. - Webhook signing secrets are encrypted at rest with the connection at-rest key when one is configured. Existing plaintext rows stay readable and are encrypted on their next write. - The Cloud Run demo deploy workflow passes the triggering run's branch name to the shell through an environment variable and validates it as an image tag. ## [0.108.3] - 2026-10-08 ### Performance - Postgres job reads no longer transfer and decode every job payload on each call. A read sends the row versions this process already holds, and the database returns a payload only for rows that changed, so another replica's write is always seen. Payloads are cached as JSON text per tenant, with a byte limit (`AGENT_BOM_POSTGRES_JOB_PAYLOAD_CACHE_MB`, default 256). Reads outside one request's aggregate read still parse a fresh job. - A cold `/v1/posture` now parses each job payload once instead of three to four times. Latest-scan selection, the overview fold, the current-graph resolver and the finding spine share one parse of each exact payload within the request, on Postgres and SQLite. A changed row is new payload text and is parsed again, so another replica's write is still seen. Latest-scan selection also moved off the event loop. On the demo estate (one 43 MB job), the first `/v1/posture` after a restart drops from 2.6 s to 1.7 s on Postgres and from 2.4 s to 1.7 s on SQLite (median of 3 restarts); the first `/v1/overview` and `/v1/findings` also drop by 0.3-0.7 s. - Campaign reconciliation now reaches its checkpoint, so it stops re-walking and re-redacting every finding at each boot and every maintenance tick while evidence is unchanged. A campaign walk reuses one read context across its pages, and the background walk is no longer cut off by the 10 s request bound. ### Fixed - A nested package-vulnerability row now folds onto the finding on its own MCP server when other assets share the same package version, instead of surfacing as a duplicate row with no finding identity. The demo estate reports 2,711 findings, not 2,719. A nested row that still matches no finding gets a deterministic `canonical_id`. Campaigns still treat a row without an identity as an incomplete collection. - Campaign collections no longer stay incomplete on Postgres. Resumed cursor pages intentionally omit the total, so only the first page's exact total binds the walk, and any later page reporting a different total still fails the walk. ## [0.108.2] - 2026-10-08 ### Changed - Move the PyPI and Docker Hub front doors to `docs/registry/`, the repository map to `docs/PROJECT_STRUCTURE.md`, the image exception register to `docs/security/image-exceptions.yaml`, the project-config template to `examples/agent-bom.yaml.example`, and the fuzz harnesses to `.clusterfuzzlite/fuzz/`. ### Removed - Remove the legacy Streamlit dashboard, the `agent-bom report dashboard` command and the `dashboard` install extra (which also left `agent-bom[all]`). Use `agent-bom serve` for the bundled dashboard. ### Performance - The first `/v1/posture` and `/v1/graph` after a restart no longer compete with background work. Campaign reconciliation and the demo story prewarm wait until no request is in flight and a quiet window has passed, and they run after at most 60 s even under steady traffic. Current-estate graph reads now run concurrently. Rebuilding or retiring a generation still waits for active readers, and the 409 retired-generation contract is unchanged. ### Fixed - Match RHEL/UBI advisories and fixes to applicable product streams. Keep unknown fix status and incomplete assessments explicit after suppression. - Retain available current-estate evidence when a scan has no graph, preserve unrelated inventory and authoritative clean replacements, and represent valid empty estates without masking storage failures. - Preserve validated package identities and PURLs through redaction. Use ecosystem-appropriate Go and NuGet lookup spelling and invalidate older OSV cache entries that may contain incomplete matches. - Persist configured SQLite exception approvals across restart and reject remote database URLs before SQLite can create local files. Postgres support for remaining governance stores is separate work. - Show “No assessment evidence” when an otherwise finding-free report has neither packages nor evaluated controls. - Bundle the cloud benchmark inventory, verify compiled dashboard installation pins against the wheel version, and retain the requested image platform through Docker save/export. - Resolve Maven properties from local parent POMs, retain Swift repository aliases for advisory lookup, and preserve supplied SBOM scope, package identity and recorded dependency evidence. - Keep repository IaC and filesystem coverage gaps explicit, retain Django URL reachability evidence, and inventory the CPython runtime in container images with applicable advisory checks. - Bound campaign reads, persist Postgres campaign evidence and keep missing evidence distinct from verification results. - Preserve graph investigation scope and navigation, keep loaded evidence readable in light and dark themes, and retain the selected mobile path position when updating shareable URLs. - Update service-image runtimes and honor CPython tarfile filter rejection while retaining runtime remediation evidence. - Update the pinned Python Alpine image and dashboard icon, accessibility and table dependencies. - Record OSV response-cache use and the default unfixed OS-advisory suppression count in scan JSON. - Require executed, successful dashboard validation, export and browser jobs on the exact main release commit; run those UI lanes on every main push. - Verify campaigns on default single-node deployments where jobs and hub findings are in memory and campaign workflows use SQLite. - Keep SPDX 2 and SPDX 3 packages marked APPLICATION in scan inventory instead of omitting them. - Keep letter-suffixed Debian, Alpine and RPM fix versions such as tzdata `2025b-0+deb11u2`; they were misread as prereleases and their advisories hidden as unfixed. - Return compact `/v1/findings` list rows with `controls_count`; request full control mappings with `?include=controls` (CLI `--include-controls`, SDK `include_controls`). Reuse scan rows within posture reads to cut cold posture and remediation latency. - Treat Glama listing lag within 72 hours of a release as pending provider sync, and report the underlying Smithery catalog error with a longer convergence window. - Build the graph scale-evidence server image from the current source tree. - Reuse the persisted current-estate graph projection across server restarts when evidence is unchanged, instead of rebuilding it in every process. ### Security - Allow valid bearer access-token reuse while retaining replay protection for one-time OIDC exchanges. Honor explicit role claims, including viewer, and reject non-string tenant claims. - Remove request queries from both API launchers' access logs, redact short bearer tokens and control-plane keys, and suppress interpreter warnings that echo scanned source or filenames. - Reject malformed compliance ingestion bodies before writes and require an explicit JSON boolean for absent-finding reconciliation. - Sign the exact audit response bytes and reject malformed, past or timezone-less explicit exception expiries without changing separate approval requirements. - Pin webhook socket connections to validated DNS answers, block cloud metadata destinations, and require both tenant and operator opt-in for private subscription destinations. Disable automatic redirects and ambient proxies for inline delivery. - Keep `GET /v1/agents` read-only and scope demo agents to the showcase tenant; live host discovery stays behind the operator binding. - Return 503 from `POST /v1/auth/saml/relay-state` when SAML is not configured instead of recording a nonce. - Bound suppression expiry (`AGENT_BOM_EXCEPTION_MAX_EXPIRY_DAYS`, default 365) and reject approval by the requester or by the author of the suppressing triage or VEX decision unless `AGENT_BOM_EXCEPTION_ALLOW_SELF_APPROVAL` is set. Postgres deployments need migration `20261007_03`. ## [0.108.1] - 2026-10-06 ### Fixed - Reconcile default inventory and graph reads with the current tenant estate across REST, MCP and the dashboard. Retain clean assets, unrelated targets and partial evidence; preserve explicit historical views and reject stale pagination generations. - Load configured persisted scan evidence in standalone MCP before API startup, including base installations without API extras. Propagate configured storage failures instead of silently returning an empty estate. - Redact bearer credentials and short JWTs through pushed and persisted evidence. Retain safe IaC file/line labels, classify repository IaC as application evidence and apply only approved, active suppressions to finding filters. - Preserve imported server identities and validate actual HTTP report and graph exports against their published schemas. - Replace the permanent inventory detail panel with a keyboard-accessible drawer, collapse secondary metadata and improve mobile and light-theme readability. Explain graph connectivity separately from severity and derive freshness banners from displayed evidence. - Reduce repeated finding decoding and reconciliation, bound remediation projections and defer collapsed campaign requests. Refresh desktop and mobile product captures at documented viewport sizes. - Keep console verdicts coverage-aware for incomplete imported inventories and lookup warnings. Correct the bounded GitHub Action Dogfood fixture and ensure fixture changes run its workflow. - Preserve SARIF source locations, CycloneDX nested components and distinct imported server identities. Keep suppression state and recorded reachability evidence explicit in findings. - Restore inventory empty-state handling, persistent dashboard theme selection and remediation across current scan targets. - Refresh output characterization contracts and bundle framework catalogs in frozen fuzz targets. - Preserve OSV upstream CVE relationships through local database sync, scanning, EPSS/KEV enrichment, findings and SBOM round trips without merging those links as aliases. - Align Ruby artifact identity regressions and changed-domain CI selection with recognized native-platform normalization. - Bound gateway and proxy policy regex execution; reject unsafe pattern structures and fail closed on oversized inputs or exhausted match budgets, with explicit audit-mode receipts. - Match recognized native Ruby artifact versions using the underlying gem version, retaining platform evidence. Resolve uv workspace members from their shared lockfile; missing or malformed locks remain incomplete instead of falling back to registry-selected versions. - Require separate authenticated admin approval, exact finding/package scope and a future timezone-aware expiry for suppression. Feedback, triage, MCP and imported VEX requests remain pending; legacy automatic approvals require reapproval. Retain VEX assertions as evidence without silently changing risk or exit gates. - Report configured filesystem exclusions separately from collection failures. Git metadata, ignored paths and duplicate worktrees remain visible scope receipts without forcing partial scans or secret-scan error exits; unreadable paths, symlinks and exhausted budgets remain incomplete. - Restrict new-tenant invitations to platform-operator admins whose scope ceiling permits the delegated key. Require attributable authorization receipts in both tenants before provisioning; reject customer-admin recursion and scoped-key escalation without creating tenants or keys. - Reject malformed and oversized gateway policy regexes before writes. Existing invalid blocking rules fail closed, audit rules expose the invalid policy explicitly, and standalone gateway and proxy evaluation share the same validation. - Cache OSV results only after every package query succeeds. Failed, malformed, truncated, and incomplete alias/ecosystem lookups remain retryable; a new cache-key generation excludes older potentially incomplete results. Incomplete scans no longer print a clean or complete-report claim. - Keep pushed findings scoped to the producer and explicit scan target. Complete rescans replace only their own target, partial scans preserve prior evidence, and older unscoped pushes remain independent observations with a coverage-neutral warning. - Run redaction traversal and generated-metrics contracts on relevant pull requests. Verify Postgres collated-index readiness separately from the planner's choice between eligible indexes. - Preserve the stable, redacted CLI input-error message for malformed SBOM JSON, duplicate keys and non-finite values. - Restore the cloud-inventory extension when importing CycloneDX or SPDX JSON through CLI, API and MCP scans, including cloud-only documents. Retain imported provenance and collection gaps, reject malformed or ambiguous extensions, and preserve imports alongside fresh cloud observations. - Retain collected cloud inventory, native scope, environment tags and collection warnings alongside CycloneDX and SPDX software BOMs in a redacted, versioned evidence extension. Include these artifacts in the offline connected-BOM example. - Preserve recognized Azure ARM IDs, AWS ARNs and GCP resource coordinates across structured report and graph redaction, including resource-reference lists. Continue redacting embedded or encoded credentials and mask local Windows paths in identifier fields. - Preserve recorded package-to-package dependency relationships in CycloneDX and SPDX exports. Resolve parents within the same server and ecosystem, keep ambiguous or missing lineage explicit, and retain distinct package URL identities. ### Security - Upgrade locked Mako, multidict, Werkzeug and source-map-js dependencies to versions that passed the repository advisory gate; raise the Werkzeug dependency floor. ## [0.108.0] - 2026-10-03 ### Added - Inspect component hierarchy, recorded relationships, collector names and timestamps through bounded REST/MCP inventory pages and the dashboard. Snapshot-generation checks reject stale continuations; page completeness remains distinct from source collection coverage. - Navigate from inventory to exact component findings and control evidence without losing the retained snapshot. Export loaded evidence with source records and completeness receipts. - Distinguish control mappings from explicit failed benchmark checks, including resource versus account scope. Missing results and supporting detail remain visible; account results are not inherited by child resources. - Reproduce dependency parsing, component investigation and a changed-input rescan with `scripts/prove_connected_bom.py`. The credential-free example retains SQLite snapshots and compares authenticated REST and MCP evidence in tests; modeled cloud topology is explicitly synthetic. ### Fixed - Accept slash-containing native cloud identifiers and scoped package identifiers in inventory detail URLs. - Map known Apache Maven namespaces to the NVD Apache vendor and compare OpenSSL alphabetic release suffixes in affected-version ranges. Correct the bounded Apache HTTP Server regression fixture. - Keep the experimental Neptune unsupported-operation test aligned with the bounded inventory reader and run it in targeted graph/inventory checks. ### Security - Remove the vulnerable braces/micromatch dependency chain from Next ESLint root discovery using a scoped maintained glob replacement. Preserve advisory enforcement and test directory discovery and the actual lint rule. ## [0.107.2] - 2026-10-01 Version 0.107.1 was tagged but not published; its prepared changes are included here. ### Fixed - Query release CI by the candidate commit so unrelated workflow history cannot hide its successful main run; retain exact-main and completed-success checks. - Queue same-process SQLite graph mutations in arrival order before schema setup, preserving bounded contention errors, failed-producer rollback and concurrent initialized readers. - Keep SQLite graph startup metadata repairs indexed after migration, and reinitialize read schema state when a database is replaced at the same path. Late legacy relationship metadata remains repairable. ### Security - Validate both published container architectures by immutable image identity, retain vulnerability reports before enforcing release gates, and archive original daily-rescan SARIF evidence. - Require Tornado 6.5.10, including the 6.5.9 security fixes and follow-up static-file compatibility repair. - Preserve installed-package self-scan findings in GitHub uploads by anchoring them to retained generated evidence; keep the original SARIF and the severity gate unchanged. ### Added - Map bounded, explicitly configured warehouse-export rows into versioned graph evidence through `agent-bom ingest warehouse`, preserving tenant-scoped identities, recorded context and observation times with unknown collection coverage. - Add independent-process graph storage qualification, content-verified restart receipts and an authenticated public-contract consumer probe with bounded, revision-pinned evidence pages. - Version the graph interchange and node-evidence provenance contracts. Preserve recorded source and observation metadata across graph JSON, REST, MCP and entity details without treating collector names as successful execution. - Export a selected graph entity's loaded recorded relationships as an investigation JSON bundle. Preserve the snapshot generation, canonical entity/finding identifiers, relationship evidence, page completeness and a return link; disclose unknown collection coverage and unsigned local-export provenance. - Saved graph views notify when a newer snapshot of the same kind is available. Open it explicitly or keep the current investigation; background metadata checks preserve the pinned snapshot, selection and viewport. ### Fixed - Preserve structured SQLite failure diagnostics and verify identical page-content contracts in thread and process graph qualification. - Keep blast-radius counts, bounded canvases and entity details on one committed snapshot revision. Preserve recorded context relationships and disclose traversal lower bounds separately from the visible map. - Pin graph, search, agent-selector, attack-path and rollup continuation to committed read revisions, separately from write ownership. Reject replaced snapshots and preserve evidence-first queue order in the investigation UI. - Backfill committed graph read revisions through PostgreSQL bootstrap as well as migrations; preserve tokens on replay. Count only authoritative queue paths in investigation headings and retain actionable guidance for unsupported backend paging. - Serialize SQLite graph schema inspection and backfill with other writers to prevent startup lock-upgrade races during concurrent ingestion. - Avoid repeated normalization of absent exposure attributes during cold graph rollups while retaining aggregate counts and filter semantics. - Keep routine snapshot polling out of the graph layout; show update controls when a newer snapshot or a failed check needs attention. - Keep filtered attack-path investigations pageable when no loaded path matches. Retain loaded evidence after a failed page request and reject pages from a different tenant or snapshot. - Use finding severity for investigation filters independently of path priority, and preserve recorded bidirectional witnesses when an attack path traverses them in reverse. ## [0.107.0] - 2026-09-30 ### Added - Guided first scans connect an empty workspace to scan and connection actions, with browser-local report previews and an explicit return to live evidence. CLI quickstart prints the saved report, package-CVE coverage boundary and exact graph snapshot link. - Context Map supports Auto, Horizontal and Vertical layouts, bounded recorded-relationship inspection, and separate Fit all and Readable view controls. Collapse preserves independently loaded branches and reframes the remaining canvas. - Local readiness checks work without network probes and retain skipped or incomplete states. Imported reports disclose partial or unknown collection coverage; file timestamps remain distinct from successful live scans. - Export and validate an experimental per-agent BOM from an exact agent in a completed scan through CLI, API and dashboard. The profile retains source and coverage references; structural validation does not establish evidence authenticity or compliance. - Authenticated read-only Jamf Pro and CrowdStrike Falcon inventory sync with encrypted credentials, resumable collection, tenant-isolated SQLite/Postgres evidence and explicit freshness/collection gaps. Manage connections through the API, CLI and a bounded Connections → Endpoints tab; inspect inventory and run authorized syncs through MCP. Sensor health remains distinct from policy compliance. ### Security - Require PyJWT 2.15.0 or newer so deeply nested JWT payloads raise documented token errors before signing-key lookup (CVE-2026-101918). - Require urllib3 2.8.0 or newer for HTTPS proxy TLS isolation, bounded chunk-size parsing and terminating Deflate streams (CVE-2026-97687, CVE-2026-97688, CVE-2026-97689). - Bind anonymous API exemptions to exact HTTP operations and reject unclassified protected operations. Scope scheduled work, source records and export operations to explicit tenant authority; revalidate stored credentials on active streams and reconnects. - Reject malformed entries throughout browser-imported reports, including decoded structural keys, oversized UTF-8 input, invalid exposure labels and inconsistent severity totals. Rejection messages do not echo report contents. - Keep trace correlation tied to the submitted input and authenticated session. Invalid gateway enforcement settings fail before startup, and failed visual screening withholds upstream results. ### Changed - Findings pages (`/v1/findings`, `/v1/compliance/hub/findings`) order findings that tie on score and timestamp by code point of `canonical_id` (and `last_seen` / `first_seen`) on Postgres, matching SQLite. Previously a Postgres database with a locale collation such as `en_US.UTF-8` could order those ties differently. Existing cursors keep working. The Postgres migration `20260928_01` adds `COLLATE "C"` versions of the findings sort indexes, built concurrently, so every sorted page stays an index scan; a cursor page now seeks directly to its position instead of filtering the rows before it. ### Fixed - Self-scan SARIF advisories retain their installed-environment identity as a logical location, avoiding GitHub's rejection of non-file source URIs. Real package manifest paths and lines remain physical locations. - Retry bounded SQLite WAL startup contention when graph reads overlap initial graph creation; close failed startup connections and continue to reject non-contention database errors. - Resolve CommonJS namespace aliases for command-execution analysis, including `node:child_process`. Readiness checks distinguish the OSV lookup cache from the vulnerability database and report the same database staleness threshold used by scans. - Malformed CloudFormation template, resource and policy containers no longer abort a repository scan. Reports retain findings from valid resources and mark unevaluated input as partial coverage; IAM policies with a single Statement object are evaluated. - Preserve the finding occurrence and source scan across graph investigation. Exact snapshot and canonical entity links work across Context Map and Agent Mesh without substituting another entity when a lookup fails. - Show recorded relationship endpoint labels, direction and canonical identifiers with bounded incident pages. Preserve loaded pages across responsive layouts and disclose unavailable labels, unknown totals and stale evidence. - Serialize finding ingest across replicas and share atomic ledger/current-state writes. Tenant-scoped job keys, owned dispatch leases and generation-fenced graph rollback preserve concurrent work. - Align REST and MCP graph exposure evidence, preserve cloud resource scope and native identity in graph joins, and bound page projection work. - Exclude generated source trees and benign JavaScript calls from relevant scanner analysis; preserve explicit coverage gaps when analysis is incomplete. - `POST /v1/scan` now runs the same secret scan as `agent-bom scan -p` for `agent_projects` and `filesystem_paths`, not only for `repo_url` clones. - MCP `scan` queries vulnerability sources online by default (honoring `AGENT_BOM_OFFLINE`), returns a bounded, always-valid JSON summary with paged `result_id`/`section` follow-ups (`detail="full"` for the whole document), sets `isError` on incomplete or failed scans, and accepts extra workspace roots via `AGENT_BOM_MCP_WORKSPACE_ROOTS` or `agent-bom mcp server --workspace-root`. - `--external-scan` no longer disables project auto-detection (IaC, SAST, secrets); when another input does skip it, the scan warns. - External SARIF results are mapped by rule type: dependency advisories resolve to the real package@version and merge with native matches, code results stay SAST findings with file and line and merge with the native finding. Merged findings keep both `native` and `external:` source labels. CycloneDX and SPDX inputs to `--external-scan` import their vulnerabilities, or are ingested as an SBOM with a notice. - Redaction keeps finding titles, secret types and credential variable names readable (`Hardcoded credential: Stripe Key`, `secret_type: api_key`) while still redacting values. - A password in a database connection string (`postgresql://user:pass@host`) is a critical `Connection String` credential, not personal data. - npm and PyPI version ranges are resolved (lockfile first, then registry metadata) instead of being floored to a version; an unresolvable range stays unresolved, is not matched against advisories, and never appears in purls, CycloneDX or SPDX. - Online and offline scans derive severity from one documented CVSS precedence, so `--fail-on-severity` no longer depends on mode. - `--fail-on-kev` fetches only the KEV catalog when `--enrich` is not set, accepts a fresh local DB as KEV evidence, and prints the remedy when it fails closed, including under `-q`. - `--license-check` reports `status: undetermined` with license coverage when licenses are unknown, instead of `compliant: true`. - Withdrawn advisories are skipped by the GHSA database sync and removed from the bundled demo data. ## [0.106.1] - 2026-09-26 0.106.1 is the first published release of this line. The `v0.106.0` tag exists but its release run stopped at the version guard before building anything, so 0.106.0 was never published to PyPI, Docker Hub, Helm or GitHub Releases. ### Security - Scope `GET /v1/graph/exposure-paths` and `POST /v1/graph/should-i-deploy` to the authenticated request tenant. These REST routes previously resolved the MCP process tenant, so on SQLite every tenant received the `default` tenant's credential-exposure paths and deploy verdict, and on Postgres with row-level security every tenant received an empty result. - Keep demo estate data out of product stores. Demo mode now pins every local store to `AGENT_BOM_DEMO_STATE_DIR` (default `/demo-estate`) before any store opens, refuses explicit store paths that point into product state, and refuses to seed over a non-demo snapshot. ### Added - Bounded relationship paging across SQLite, Postgres, REST, and persisted Context exploration. Tenant-scoped cursors and generation checks prevent combining evidence across replaced snapshots. - Inspect recorded authority and source receipts at each graph path hop, with bounded pagination and preserved investigation scope. - Optional, bounded AWS credential validation through STS, disabled by default and suppressed by offline scans. Validation errors remain unknown without removing findings. - Add an explicitly configured Snowflake workload-identity adapter for scan connections, binding each delegation to the authenticated tenant and injected SPCS account and rejecting caller-selected roles or credential fallback. - Add collapsible asset-type and name/ID/context filters to the environment scope summary, with bounded, expandable relationship details and indexed incident pagination. - Group estate assets by recorded provider, account, and environment, and focus an asset and its connections through the shared evidence drawer. - Add tenant-isolated, retry-safe comparable finding history with on-demand history charts and a values table, extending `/v1/trends` additively with bounded metadata retention. - Add bounded environment-group navigation with aggregate recorded relationships, retained camera state, and searchable asset/relationship controls. - Python one-hop tainted-argument evidence for function-reachable CVEs. This additive signal does not establish exploitability or full interprocedural data flow. ### Fixed - Distinguish conditional and unknown IAM admin evidence, recognize account-wide IAM policy scope, and expose the assessment in collapsible identity details. - Continue browser extension discovery when a Chromium profile directory is unreadable and mark the resulting coverage gap. - Match fix-first agent filters by canonical identity or display label, expose additional loaded Context relationships, and simplify security-area summaries. - Refresh stale local vulnerability coverage through OSV during online scans while preserving offline behavior. - Preserve structured report identifiers during redaction without exempting embedded credentials. - Bind exposure pagination to snapshot generations and reject NUL graph identifiers before database access. - Calculate CVSS v4 scores with the macrovector algorithm, preserving the correct severity at build-gate thresholds. - Keep curated demo agent discovery independent of host configuration and serve matching agent detail and lifecycle routes. - Accept unknown severity when importing JSON reports. - Retain findings totals when the count cache expires during an in-flight request. - Evaluate collected IAM policy documents before assigning unconditional admin-equivalence labels, including explicit denies, resource scope, and unresolved conditions. - Repair Snowflake Native App installation contracts and reject unsupported scan dispatch explicitly. - Explore persisted Context connections with canonical agent IDs, compact canvases, explicit paging and collapse, and selected relationship labels. Clear stale or account-scoped evidence and resolve graph IDs without downloading full scan reports. - Persist tenant-scoped export destinations on Postgres and preserve unknown vulnerability scores in warehouse feeds. - Preserve shared scan jobs across replica startup and bind dispatch lease updates to the owning claim. - Connect scoped agent investigation to permission receipts, advisory prerequisites, directional neighbor expansion, and exact-agent runtime activity; retain recorded runtime event references consistently in REST and MCP. - Bind graph vulnerability relationships to matching package owners, preserve package-specific evidence, and reject contradictory server matches. - Require exact agent and tool identities for related runtime activity; distinguish scan configuration from execution and make Context Map relationship evidence inspectable. - Reconcile final terminal severity totals with JSON after SAST scanning, enrichment, and filtering. - Accept nullable advisory scores and current CLI tool fields when importing JSON reports. - Keep imported report findings separate from tenant posture, coverage, services, and scan freshness; label tenant-wide compliance exports explicitly. - Select ranked Context Map paths with keyboard support, discard stale scan responses, and preserve readable path drawers and graph framing across themes and viewport sizes. - Preserve distinct authorization receipts, action-specific evidence, workload connections, and source witnesses across graph and exposure responses. - Require evidence before reporting verified remediation, and keep runtime outcomes separate from exploitability signals. - Improve scoped inventory, findings, compliance drilldowns, graph framing, and light/dark metric readability. Empty API snapshots now return an empty summary. - Preserve dashboard metadata in refreshed images and enforce deployment and registry freshness checks while retaining Smithery as an explicitly non-blocking surface. - Keep screenshot proof sensitive to rendering toolchain and resolved dependency changes while allowing Node type-only maintenance updates. - Persist Native App graph and control-plane evidence, including the audit signing key, on an encrypted per-tenant volume so restarts preserve verification. - Support opt-in external OAuth verification for remote MCP with a pinned issuer/audience and bounded token lifetime, and obtain fresh read tokens for deployment probes instead of embedding credentials in command arguments or logs. The public server card advertises the `oauth2` scheme in that mode and `bearer` only for static credentials. - Render the agent mesh from paged persisted graph relationships, publish Native App audit keys atomically under a directory lock, and expose Snowflake workload onboarding only in Native App mode. - Retain supporting agent identifiers and minimum hop distance when converting blast-radius results into finding rows, so corroborated reachability evidence is no longer dropped during response sanitization. - Align demo agent-to-MCP-server relationships across the estate graph, fleet server counts, and MCP observation agent lists so they no longer diverge. - Reject malformed SCIM `active` values instead of coercing them into lifecycle changes, and retry idempotent credential revocation when deactivation is repeated after a store failure. - Preserve declared agent model and tool associations, including positional LangChain `initialize_agent(tools, llm)` calls, so tool and data-flow findings are retained. - Distinguish unassessed graph-node risk from scored evidence, showing "Not assessed" consistently across graph inspection, search, and inventory while preserving an explicitly assessed zero score. - Bound initial graph requests to 250 ranked assets with explicit partial counts, loading the broader selection only on request while keeping full-estate search available. - Preserve readable graph framing and the investigation root after closing details, and stop native filter navigation from interrupting incoming client navigation. - Add bounded, stable-identifier search to discovered identity rows, and bound API response caching to 64 entries with least-recently-used eviction and expiry cleanup. - Keep copy-paste install surfaces on the latest published release. GitHub Action refs, pull-only Compose and Kubernetes image pins, Helm/bundle commands, and consumer pre-commit revs now track `PUBLISHED_VERSION`, which the release run advances only after publishing, so docs on `main` no longer point at an unreleased tag or image. - Keep the daily `latest` image refresh labelled with the rebuilt release version when it applies the default branch's runtime security overlay, so the Docker Hub README sync no longer fails its release consistency check. - Stop printing the ephemeral audit-signing-key warning in CLI scan output. It is now logged at API startup and when an audit entry is first signed without `AGENT_BOM_AUDIT_HMAC_KEY`. - Replace the "Contact your administrator" dead end on the dashboard login when the API was started without any key. The page now shows the restart commands (`agent-bom api --api-key `, or `--allow-insecure-no-auth` for local use); authentication behavior is unchanged. - Point CLI help `Docs:` links at the documentation site, and stop directing users to the `mcp-server` extra for `agent-bom mcp server`, which works from the base install. - Fetch every release tag in the release version guard. A tag-push checkout carried only the pushed tag, so the guard reported the published release as untagged and stopped the release. - Store OSV version pins only when no stored range already matches the version, shrinking the PyPI advisory table from 1.34M to 44k rows (204 MB to 12.6 MB) with identical match results. Existing databases shrink on the next sync. - Rescore stored CVSS 4.0 vectors at read time, so databases synced before the CVSS 4.0 fix no longer report inflated severities, including read-only databases. - Count unreadable Firefox/Chromium extension entries, discovery probes, MLflow runs, and dpkg `status.d` directories as coverage gaps instead of aborting the scan or, on Python 3.14, skipping them silently. - Match MCP registry and `fleet_scan` entries by exact package identifier (version stripped, PEP 503 names for PyPI, no match when ambiguous), so local servers are no longer labelled as unrelated third-party packages. - Follow markdown paragraph rules in skill audit, so a negated instruction wrapped across lines is no longer reported as a critical bypass. - Start SAST taint analysis at Flask, Quart, and FastAPI route handlers, not only MCP tool handlers. FastAPI `Depends()`/`Security()` parameters are not treated as sources. - Give graph agent nodes the risk score and severity of the worst vulnerability they reach. Agents that reach none stay unassessed rather than scoring zero. - Set `graph_reachable`, minimum hop distance, and reaching agents on CLI scan findings from evidence-bearing scan graph paths, using the same rule as the API. Topology-only paths still leave reachability unset. - Page `GET /v1/graph/rollup?node=` drill-down with `offset`/`limit` (default 200) instead of returning every child, and support rollup on the Neptune backend. - Show one findings count across the nav badge, dashboard, and findings page. `/v1/posture/counts` adds `issues` (issue-group counts matching the page) and `agents` (distinct agents in the tenant's current graph snapshot); occurrence totals are unchanged. - Report a slow or failed enterprise demo build as loading or failed instead of "not enabled". - Open the graph on the first level that offers a choice, and offer retry or a bounded map when a rollup fails instead of falling back to the raw topology. - Advertise `oauth2` in the MCP server card when an external OAuth issuer protects the transport. ### Changed - Increase opt-in DSPM object sampling from 10 to 50 objects per bucket/container and database sampling from 100 to 500 rows per table; byte and cell limits remain bounded. - Update dependency and CI action pins, registry metadata, and operator documentation. - **Upgrade note:** with `AGENT_BOM_STATE_DIR` set, assets, local analytics, history, baselines, report artifacts, outboxes, and catalogs now live under that directory instead of `~/.agent-bom`. SQLite deployments without `AGENT_BOM_DB` keep graph scenarios in the state-directory control-plane database instead of `./agent_bom.db`. Existing files are not migrated; move them before upgrading to keep them. - `agent-bom api --persist` now sets `AGENT_BOM_DB` like `serve`. - The README opens with the agent context map, self-host and deployment models; the quick-start sample output is collapsed. ## [0.105.0] - 2026-09-15 This release makes scan coverage and finding evidence clearer, adds explicit credential validation, and improves the path from findings to investigation. ### Added - Opt-in `agent-bom secrets --validate-credentials` checks for supported GitHub and Stripe credentials, with bounded read-only requests and `valid`/`invalid`/`unknown` verdicts. Default scans make no validation requests; unsupported credentials remain unknown and finding severity is preserved. - Optional Iceberg REST OAuth scope and token-endpoint configuration for Apache Polaris, alongside existing credential and bearer-token authentication. ### Fixed - Align the PyPI description with the seven shipped MCP resources and check resource/prompt counts in lists that contain serial commas. - Report excluded ancestor directories through shared scanner coverage and API outcomes so an uninspected scope cannot silently appear complete. - Preserve structured CWE identifiers in the finding drawer and standard SARIF taxonomy relationships, including findings without CWE text in their prose. - Scan upstream JSON-RPC errors, notifications, and response metadata through shared proxy/gateway DLP. Inspect malformed stdio output in audit mode and drop it in enforce mode; preserve the configured handling of detected secrets. - Reap the proxy child on SIGTERM and wait for normal server exits before sending shutdown signals. Forced termination with SIGKILL cannot run cleanup. - Resolve positional tool arguments for supported LangChain agent constructors, including imported aliases, so tool and data-flow findings are retained. - Reconcile canonical finding occurrences across scan and hub ingestion in findings, exports, and Overview counts. Hub-managed lifecycle and enrichment take precedence; findings on distinct assets remain separate. - Accept bounded compressed report uploads, reconcile package versions without merging ambiguous findings, and evolve the additive Parquet/Iceberg schema while preserving existing field identifiers and rows. - Describe remediation taxonomy mappings without implying that controls have passed, and keep the summary aligned with the filtered packages. - Keep the full posture Overview first and Top risks in a second tab. Lead risk summaries with affected workloads and conditional impact, with package, advisory, and path details available on expansion. - Admit graph requests before expensive reads, preserve the canvas during background refresh failures, and restore bounded drill-in, direction/depth controls, relationship navigation, and actionable empty states. Reserve space for desktop detail drawers so focused nodes remain visible beside them. - Reduce concurrent SQLite roll-up latency with batched topology reads while retaining complete counts, tenant scope, and consistent snapshots. Attack-path investigations continue to load full evidence. - Preserve OSV enumerated affected versions alongside ranges, including mixed GIT and ecosystem advisories such as Pillow's CVE-2022-45199. Existing local databases need an OSV refresh after upgrading: `agent-bom db update --source osv --osv-ecosystem PyPI` (repeat for other ecosystems in use). - Paginate asset inventory and organize Identity and Audit tasks into tabs; simplify Fleet and Connections, remove displayed identity token prefixes, and distinguish evaluated controls, risk mappings, and unavailable checks. - Use published package versions and real advisories in clearly simulated demo scenarios; refresh Overview and framework screenshots to match the application. - Preserve repository inventory as code assets in graphs and retain durable report-export work across replica recovery. ### Changed - Reuse the dependency-audit baseline only when its frozen Python inputs are unchanged; fail the OSV gate on scanner errors or invalid reports. - Skip redundant CodeQL analysis on prose/image-only main pushes while retaining pull-request, merge-queue, scheduled, and manual analysis. - Refresh supported dependency pins and release-registry verification checks. ## [0.104.0] - 2026-09-08 This release improves the path from scoped scans to shared findings, operator review, and opt-in runtime controls. AI spend remains an estimate of recorded token usage; runtime receipts distinguish reported behavior from producer assurance. ### Fixed - Preserve live gateway activity through the production dashboard proxy and resume from the last event cursor after reconnect. Postgres identity upgrades add the managed-profile lookup while preserving legacy installations that have not provisioned identity storage. - Upgrade the dashboard's YAML parser and image-processing dependencies to js-yaml 4.3.2 and sharp 0.35.4. Distribution freshness checks now pass their configured timeout and retry budget to the Glama probe. - Preserve the imported report’s scan ID in finding links so investigation opens its persisted graph snapshot. - Keep AI spend visible within Overview coverage, with compliance and top risks directly below the main cards. - Keep advisory fixes scoped to their package and affected range; unknown fixes no longer inherit another package’s version. - Focused investigation graphs retain identity and data nodes that belong to the selected path, even when those layers are hidden in the broader estate view. - Scan caching honors `AGENT_BOM_STATE_DIR` in read-only containers while preserving explicit cache-path overrides. - Headline AI spend, call, token, and agent totals cover all retained matching records across memory, SQLite, and Postgres. Detail history is bounded and labeled; unavailable storage, unpriced calls, and unsupported forecasts stay explicit. Tenant budget fallback uses tenant spend. - Runtime event retries preserve canonical identity across new HTTP request traces. Submission origin, reported producer origin, receipt metadata, and unknown or caller-asserted producer assurance remain distinct in persisted records, feeds, metrics, and activity views. - Disk side-scan retries bind to the full request scope. Setup failures and incomplete cleanup retain recovery evidence; failed unmounts preserve owned temporary resources for inspection. - Skills scans retain the authenticated tenant in audit evidence and use configured SQLite result storage. Unsupported remote result backends reject scans before side effects; the UI clarifies mounted target scope, empty results, and unavailable evidence. - Findings preserve observation anchors and SLA deadlines. Dashboard coverage, framework marks, finding columns, graph framing, and mobile cost tables are easier to inspect in light and dark themes. CLI help avoids duplicate commands. ### Changed - Manage server-side runtime profiles with `agent-bom runtime profiles` create/list/validate/test commands, the API clients, and the dashboard. Validation and test previews evaluate configured bindings; they do not authenticate a caller or authorize a live tool call. - Follow persisted gateway activity with `agent-bom runtime feed --follow --cursor-file ./activity.cursor.json`. The dashboard uses authenticated SSE with cursor backfill and explicit disconnected or degraded states. See `docs/RUNTIME_REFERENCE.md` for retention and deployment proof boundaries. - Runtime evidence ingestion now requires an expiring, source-scoped API key or verified OIDC credential. API bodies, MCP arguments and CLI flags no longer accept source secrets. CLI/MCP producers use the configured control-plane API; legacy shared-secret source registrations fail closed. See the runtime producer migration guide in `docs/CLOUD_CONNECT.md`. - MCP server startup now exposes eight scan and remediation tools by default. Select graph, cloud, runtime or audit profiles for specialized work, or use `--profile full` to preserve the complete catalog in existing clients. Prompts, server cards and health counts reflect the active profile; `profiles://catalog` provides discovery without loading every tool schema. Authentication, tenant scope and write authorization remain required. ## [0.103.2] - 2026-09-01 This patch makes the correlated-evidence journey automatic and easier to read, while advancing the maintained dependency and MCP-registry baseline. ### Changed - The committed reference evidence lab now executes the real repository, CycloneDX, Kubernetes IaC, MCP configuration, advisory, correlation, and authenticated gateway paths. Its generated proof binds every input artifact, exact-identity join, signed runtime-facts bundle, live allow receipt, and strict pre-upstream block receipt. - The evidence journey is labeled Connect, Discover, Scan, Correlate, Investigate, and Enforce (opt-in); fresh snapshots are selected by default, stale or future-dated inputs remain explicit, and completed scans always offer truthful Findings, Investigation, and Remediation handoffs. - Investigation selects the newest completed correlation when no explicit snapshot is deep-linked, keeps correlation setup secondary to the resulting graph, and presents the evidence journey clearly across desktop, mobile, light, and dark views. - Correlated path proof now distinguishes complete, directed, traversable hop evidence from incomplete or truncated receipts before presenting a path as verified. - Mobile Investigation renders long attack paths as readable sequential hops and directed relationships instead of shrinking the complete chain into a miniature canvas. - Attack-path layout now collapses according to measured canvas width before labels become unreadable, and light-theme risk cards use accessible text contrast without changing risk semantics. - Python, JavaScript, MCP, and CodeQL dependencies plus the bundled MCP registry are refreshed under their existing release and serialization contracts. - Private SQLite graph-build workspaces avoid durable fsync overhead while retaining transactional staging semantics; durable graph stores are unchanged. ### Fixed - Postgres observation migrations provision the full retained-history window as well as the future runway, so backdated connector evidence no longer attempts partition DDL through the least-privilege application role; stale deployments receive a sanitized retryable response instead of a raw database failure. - Correlation now canonicalizes exact package URLs without merging invalid or case-distinct identities, compares observation times as UTC instants, revalidates freshness when queued work executes, rejects excessive future skew, and confirms only complete directed, traversable, provenance-backed paths within their recorded analysis bounds. - MCP runtime introspection now rejects security-blocked servers before any transport is opened, keeps stdio process launch disabled by default, and requires both explicit opt-in and authenticated operator authority before a discovered command can run. ## [0.103.1] - 2026-08-29 This patch restores Alpine arm64 API-image publication and makes the release-shaped multi-architecture image proof merge-blocking for relevant Docker and dependency changes. ### Fixed - Alpine arm64 API image builds now supply the exact missing `tree-sitter-typescript` 0.23.2 build headers, and Docker input changes run the release-shaped multi-architecture gate before merge. ## [0.103.0] - 2026-08-29 This release expands repository and architecture evidence beyond MCP-only surfaces, strengthens fail-closed identity and audit boundaries, and removes large-scan bottlenecks across scanning, graph projection, SBOM ingestion, and API result delivery. ### Added - Repository scans inventory remote GitHub Actions and reusable workflows with exact-versus-mutable reference provenance across JSON, CycloneDX, SPDX, and graph exports without treating those coordinates as an advisory ecosystem. - Reachability analysis models evidence-backed application entrypoints such as console scripts, main guards, Click/Typer commands, and FastAPI/Flask routes, while keeping ordinary exported functions outside the reachable set. - Tenant-scoped architecture scenarios compare current and proposed graph states with deterministic deltas without mutating observed inventory or attack-path evidence. ### Changed - SARIF files use compact JSON encoding and indexed result taxonomy references; extension taxa omit names that duplicate their IDs. The bundled demo artifact is less than half its former size without removing results, taxonomies, or evidence fields. - OIDC setup emits file references instead of client-secret values. Compose control-plane profiles load the generated non-secret env file and mount a dedicated OIDC secret directory read-only; dashboard and Helm guidance use the same file-first contract. The deprecated `--client-secret` compatibility alias accepts only `@/absolute/runtime/path`; new automation must use `--client-secret-file `. Secret bytes are never accepted, echoed, read, or written by the wizard. - The graph opens on a risk-ranked estate investigation with authoritative facets, deduplicated paths, bounded traversal, and an optional expert canvas. - JavaScript and TypeScript AST parsing plus repository ignore semantics now ship in the base installation, so first-run source and secret analysis does not depend on optional parser packages. ### Fixed - Budgeted and filtered SQLite graph loads now seek edges from the selected node ids instead of scanning every edge in the snapshot and discarding most of them in Python. - Large scans reuse canonical report and graph projections, bound legacy advisory coverage queries to inventory ecosystems, preserve distinct finding occurrences, and avoid repeated redaction and CVE materialization work. - CycloneDX dependency and vulnerability joins use authoritative `bom-ref` indexes, reducing recovered 20,000-component fixture parsing from 18.548s to 0.132s while preserving duplicate component identity. - Runtime reachability follows framework-registered tools and resolved dependencies, preserves exposure-path topology, and uses attack-path evidence rather than structural closure for reachable findings. - Compliance and overview projections exclude failed, skipped, dry-run, and no-scan jobs and require canonical, current scan evidence. - Credential and scheduler source lifecycles close cleanly, scan targets must be executable, and gateway audit delivery and tenant routing remain durable and isolated. - Purging secret-shaped legacy material from an already-retired credential reference now records one tenant-scoped, sanitized audit event without duplicating the event on idempotent DELETE retries. - Full scan-result API responses now sanitize large AI-BOM payloads in the bounded worker pool so polling them cannot monopolize the server event loop. - Image and registry release gates preserve truthful multi-architecture evidence, idempotent publication, and immediate post-release verification. ### Security - API-key delegation, browser and WebSocket sessions, SAML/OIDC state, SCIM, Snowflake state, revocation, replay protection, and shared brute-force limits fail closed when their authoritative shared state is unavailable. - Forwarded client identity is accepted only through an explicit bounded proxy depth from allowlisted transport peers; direct callers cannot spoof private network policy with forwarding headers. - Exception logging, graph scenario errors, outbound evidence, native secret findings, and repository scans use sanitized, ignore-aware projections that do not expose credential values or server internals. - PostgreSQL audit and governance writes serialize per tenant with persistent signing, while runtime and source audit paths reject fallback routing that could cross tenant boundaries or lose required evidence. ## [0.102.0] - 2026-08-23 A release-integrity and evidence-truth release. Published Python images remove runtime packaging tools and their vendored dependency trees on both supported architectures. Container evidence is accepted by GitHub code scanning, and release completion now carries image and registry fixes through independent live verification instead of leaving automated findings open until the next daily schedule. ### Added - The MCP control-plane surface now exposes 84 tools, including tenant-bound exception listing, request, and approval workflows over the same lifecycle store used by REST and the dashboard. Writes require the operator token, `findings:write`, an administrator role, and an audit reason. - Runtime self-governance ships as a policy template and blueprint with durable-versus-fallback activity labels, cursor pagination, self-posture evidence, and an operator runbook. ### Changed - Large graph snapshots open on bounded, risk-ranked decision rollups; operators can switch to the expert relationship map, traverse the proving path, and use resizable, tabbed detail drawers without loading a dense estate as the first view. Entity and relationship colors now derive from one schema. - Scan jobs expose trigger, schedule, source, vulnerability-data freshness, terminal timestamps, per-stage statistics, and the collector issues attached to a degraded stage. - Grouped findings with facets reduce and project the requested page before sanitizing and serializing occurrences, avoiding repeated whole-window work while preserving group identity and graph provenance. ### Fixed - Canonical finding identity now distinguishes non-package asset evidence, and vulnerability exceptions and local ignore rules converge on one auditable suppression overlay across console/MCP active views, JSON, SARIF, VEX, and severity exit gates. Suppressed evidence remains queryable rather than being deleted. - The dashboard uses readable light-theme surfaces for agent inventory, consistent bounded drawers, and an evidence-first overview instead of a promotional workflow panel. The public preview separates AI/MCP clients from cloud, identity, and data integrations and states that integration depth varies by surface. - Documentation SVG generation resolves the current checkout before importing product counts, preventing an older installed package from silently producing stale architecture diagrams. - Offline repository scans with a missing or unreadable vulnerability database now return the documented incomplete-scan verdict (`1`) while preserving a partial artifact, instead of misclassifying valid input as usage error `2`. - Ranked attack paths render independently from slower full-estate fix guidance, expose their correlated role chain, support bounded traversal from each hop, and transfer only the relationships that prove the returned paths. - The labeled sample estate now records an idempotent two-point posture trajectory through the production trend store, and the public scanner story links its mutation-tested OSV range-matching evidence without presenting the bounded benchmark as universal accuracy. - Graph label budgets survive accessibility normalization, persisted attack paths derive from the final projected estate, and forced demo seeding never displaces newer operator evidence. The demo now exposes and renders an authenticated graph-ownership status before constructing graph deep links. - Published amd64 and arm64 Python images install pip 26.2 with reviewed hashes, clearing CVE-2026-13346 from the shared runtime overlay. - Container SARIF normalization supplies GitHub-compatible physical context for logical exposure-path hops while preserving the original image reference. - Successful releases immediately rescan both published architectures and record immutable image identities in automated issue evidence. - Automatic forward releases fail when Smithery publication is skipped, and a successful registry run immediately rechecks every public distribution surface so stale-inventory findings close only after live convergence. - The consumer pre-commit dependency hook now scopes scans to the downstream repository instead of including unrelated workstation MCP configuration. - Baseline and history diffs keep a CVE attached to the same normalized package across version upgrades, while inventory diffs continue to report the package version change separately. - RPM scans preserve nonzero epochs, cloud benchmark PASS results require a verified account boundary, and structural dependency closure no longer masquerades as an evidence-backed reachable attack path. - Security-relevant native AST flows now surface through unified findings, SARIF, policy gates, and source-to-tool graph provenance; inventory-only LLM client calls remain inventory rather than vulnerabilities. - PostgreSQL audit and governance chains serialize tenant appends with transaction-scoped advisory locks, reconcile migration-owned guards, and require persistent HMAC signing for shared durable ledgers. - Bare ASGI startup enforces the database RLS-role preflight, while public-demo operator pages withhold deployment posture and integration diagnostics. - OWASP LLM, MCP, and Agentic Top 10 risks are reported as applicability overlays instead of passed or failed controls across REST and MCP; the MCP surface now includes the Agentic catalog and preserves scored totals. - Secret scans suppress explicit sample placeholders without hiding real assigned passphrases, and MCP prompt heuristics no longer match words such as `ecosystem` merely because they contain `system`. - Amazon Linux, Oracle Linux, and SLES package inventories now emit explicit advisory-source-unavailable evidence instead of a false-clean zero while their dedicated advisory feeds remain unsupported. ## [0.101.0] - 2026-08-16 A workflow-completion and deployment-portability release. The same finding can now move from scoped evidence through ownership, remediation, verification, and export across the control plane, CLI, MCP, and dashboard. The release also makes the self-hosted storage boundary explicit, adds portable evidence-table publication, and replaces several release-time assumptions with fail-closed proof. ### Added - Finding lifecycle operations now persist owner, SLA, ticket, remediation, retry, and verification history with tenant-scoped authorization and stable idempotency across REST, CLI, MCP, and dashboard workflows. - The dashboard guides investigations through Path → Impact → Owner and SLA → Fix → Verify, with persona-specific starts, scoped counts, progressive graph disclosure, accessible text summaries, and bounded tables. - Skills scans and AWS, Azure, and GCP workload side scans are available through the control plane, CLI, MCP, scheduler, and dashboard. Credentialed Azure/GCP acceptance remains tracked separately and is not claimed by this release. - Opt-in, disabled-by-default adoption events measure completed scans, artifacts, investigations, verification, repeat use, CI adoption, and control-plane adoption without collecting source contents, raw findings, credentials, or customer resource identifiers. - Managed Postgres readiness, capability reporting, Helm validation, reproducible scale evidence, and portable Parquet/Iceberg evidence-table publication were added for customer-controlled deployments and downstream security lakes. ### Changed - Finding, path, correlation, returned, and total counts now carry explicit source, scope, filters, completeness, and synthetic-versus-persisted semantics. - Repository scan results expose existing AI-BOM, CycloneDX, and SPDX artifacts beside the repository context graph instead of requiring a separate workflow. - Investigation lenses share one graph surface, while large estates use bounded Sigma rendering, filterable drill-downs, and readable light, dark, desktop, mobile, keyboard, and reduced-motion states. - Owner, SLA, and lifecycle state are preserved across CSV, Markdown, HTML, PDF, OCSF, CycloneDX, and SPDX exports; shared-CVE CycloneDX workflow metadata stays scoped to the affected package reference. ### Fixed - Public counts, persona language, generated metrics, registry metadata, and MCP deployment inventory now derive from checked product contracts instead of drifting independently. - Synthetic demo timestamps and auxiliary Skills, CWPP, campaign, graph, and governance surfaces are deterministic, tenant-scoped, explicitly labeled, and protected from replacing real tenant graph data. - CWPP execution lists, Skills files, findings, and blast-radius results no longer silently hide older rows or render unbounded card sets; filters and pagination are applied consistently. - Light-theme cloud evidence and graph surfaces use readable contrast and shared surface tokens. ### Release integrity - A release tag must point to the current `main` SHA and that exact commit must have a completed successful `CI/CD Pipeline` main-push run. Pending, canceled, stale, PR-only, or wrong-workflow evidence fails closed. - The release evidence matrix now covers source commit, Python distributions, dashboard, API/UI/collector images, Helm OCI, GitHub Action, MCP metadata, registries, SBOM, signatures, provenance, and the hosted demo. - CI now bounds Python and Alpine suites without weakening their assertions, isolates benchmark environment state, validates exact MCP deployment inventory, and keeps dependency-license exceptions package-scoped. ## [0.100.0] - 2026-08-11 An output-honesty release. Every local gate was already green before this work started; nothing here fixes a crash or a build. What it fixes is the gap between what agent-bom found and what it told you — findings that were computed and never surfaced, bounded reads that claimed to be complete, a scanner that reported clean where it had not looked, and two gates on the release path that could not have failed if there had been something to catch. If you run agent-bom against RHEL/UBI images, or read the executive view, or use the graph, this release changes what you see. ### Security - **Two gates on the release path could never fail.** GitHub runs an unqualified `run:` step as `bash -e {0}` — without `-o pipefail` — so `osv-scanner … | tee` exited with `tee`'s status and the `|| { … }` fixable-CVE branch below it was unreachable. That dead branch was the blocking logic in `ci.yml` *and* in `release.yml`, where the step is named "block release on fixable CVEs". Every release that passed that step passed it vacuously. The same defect was found in 17 steps across 9 workflows. Both halves are worth stating plainly: the gate could not have reported a vulnerable dependency — and, run for real against all three lockfiles, it reports none, so nothing was shipped vulnerable. `scripts/check_ci_pipefail.py` now blocks the class. - CI bootstrapped Postgres from `init.sql` alone while the Docker entrypoint mounts `init.sql` *and* `runtime-schema.sql`. Both paths ended on the same Alembic head with a different schema — `hub_findings_current_observations` partitioned with `observed_at timestamptz` on one and plain with `observed_at text` on the other. Matching heads never proved matching schemas; a `pg_dump --schema-only` diff now does. - A read-only bind mount in `deploy/docker-compose.yml` pointed at `deploy/tests` rather than the repository's `tests/`. Docker creates a missing read-only bind source as an empty directory instead of failing, so the container scanned nothing and had no way to say so. - Secret scanning no longer reports a file it never opened as clean. Files over the size ceiling and files that could not be read were returned as "no findings" and counted toward `files_scanned`. They are now named in `warnings` and excluded from the coverage count. `.tfstate` and `.tfvars` join the scanned extensions — `.tf` was already there, so the two files in a Terraform repo most likely to hold a plaintext provider credential were never opened at any size. - WebSocket streams failed open when the auth posture could not be derived, and DLP excerpts echoed the secret they were redacting. - Microsoft Graph pagination is pinned to the origin that issued the token, so a bearer token can no longer follow a `@odata.nextLink` off-origin. - The governance audit chain gained the fork guard its sibling chain already had. - Ingested `graph_reachable: true` is rejected unless the row names an agent that reaches the finding. `dependency_reach` defines reachable as `bool(reachable_from)`; a claim with no path contradicted that definition and still collected the reachability risk boost, outranking findings the engine had actually proved. ### Fixed — wrong or missing output - A `min_severity` filter no longer deletes the graph it was meant to narrow. Only findings carry a severity, so applying the floor to every node dropped the agents, servers, packages, resources and identities the findings hang off. One backend already exempted them on one code path; every other read path — both `load_graph` implementations, four Postgres sites, the Neptune adapter and the in-memory filter — did not, so the same estate answered differently depending on which store replied. Drift incidents were also missing from the in-memory rated-type list. - A graph node budget now bounds the read rather than the result on SQLite, which previously loaded the whole snapshot before trimming it. At 200k nodes under a 5,000-node budget: 270 MB peak and 22.9s before, 6.4 MB and 2.8s after, returning the same nodes. - `GET /v1/graph/search` now rejects a deep `offset` past the documented cap, as `/v1/graph` and `/v1/graph/agents` already did; both stores enforce it too. - `GET /v1/graph` documented an induced subgraph it has never returned. The edge list deliberately reaches one hop past the node list — that is what keeps a severity-ranked finding page attached to its assets — so the description is corrected and `completeness.boundary_edges` now counts the crossing edges. - Unfiltered graph statistics are served from the snapshot row on Postgres instead of re-aggregating every node on each page view, matching SQLite. At 100k nodes: 73.5ms to 30.2ms. - The hosted-demo deploy gate asserted an estate that no longer exists — exact dict equality against 20 assets, 15 observations and 4 correlations, where the seeded estate now builds 3,860 assets, 12,171 observations and 2,322 correlations. That gate runs *after* the Release workflow, so a tag would have shipped the release and broken the demo deploy in the same run. It now asserts the contract — shape, floors, and the source breakdown that is genuinely fixed — rather than a snapshot of one day's numbers. - `agent-bom demo` printed `http://127.0.0.1:8000/demo-estate` while the API serves 8422. - The advertised MCP registry size was stale on six surfaces, **two of them strings the product emits at runtime**: the `registry://servers` resource description every MCP client reads said 1,013 servers while the resource returned 1,081. `docs/skills/mcp-server-review.md` additionally claimed 940 verified entries against an actual 60 — a 15x overstatement of verification coverage on a security registry. The count is now derived from the bundled registry at registration time, and a test sweeps whole shipping-surface trees — including SVG diagrams, which the consistency check skipped entirely — rather than a hand-maintained file list. - The documented first-run command did not run: `examples/` taught `--no-update-db`, a flag that has never existed. The test written to catch exactly this read `README.md` only and validated only *path* options, so neither the file nor the flag name was in its reach. It now covers every `examples/**.md` and asserts each flag it teaches resolves on the command. - `sdks/python` had been at `0.92.0` against a `0.100.0` platform since it was bumped by hand once and then forgotten. It re-exports the client out of the `agent-bom` wheel it depends on, so it tracks the platform and is now owned by `bump-version.py`. The TypeScript SDKs stay independent on their own 0.x npm line — retagging them to 0.100.0 would fabricate ~99 releases for their consumers — and that split is now enforced rather than assumed. - The 2D graph canvas grew without bound: `drawGraph` wrote `canvas.height` from `clientHeight` on an in-flow canvas, so each draw grew the element and the `ResizeObserver` triggered the next. On a 1,241-node estate the canvas reached 21,604px and the operator was looking at an empty slice of it. Taking it out of flow holds it at 680px. - CLI help and docs advertised registry coverage as "112 to 2800+" and a "427-server" bundled registry. Both were long stale and are now stated without a count rather than re-pinned to a new one. - `CONTRIBUTING.md` claimed "7,000+ monthly installs", which nothing in this repository can substantiate. Removed rather than restated. - **RHEL / UBI / AlmaLinux / Rocky images read zero packages.** The scanner queried an `rpmdb.sqlite` schema those images do not ship, so every scan of them returned a false clean. This is the most consequential fix in the release. - The executive grade was pinned at 0% on any real estate, so eliminating half of everything moved the headline by under one point. The curve now responds to orders of magnitude rather than raw counts; a large failing estate is still an F, just a readable one. - CIS findings were titled with the state they failed to reach — a critical finding headlined "No full-admin IAM policies attached". Titles now carry the outcome ("CIS 1.16 not met: ..."), and `ERROR` says "not evaluated" rather than implying failure. - A bounded compliance or node-context read reported completeness in a word no client understood, and one backend read unbounded while the other stopped at 50,000 nodes. Both now use the shared `complete` / `truncated` / `sampled` vocabulary and the same budget. - `GET /v1/graph` returned the same edge twice whenever a page had a containment parent outside it. - `composite_risk` meant two different things on two surfaces. - CIS remediation advisories silently dropped the check's own `fix_cli` / `fix_console`, degrading a copy-pasteable command to prose. - Identity counts and the compliance matrix rendered as contradictions; an asset-type page asked for the whole estate rather than its own type; a nested count object rendered as `[object Object]`. ### Added - `GET /v1/findings?kev=true` filters to known-exploited findings (and `false` for the inverse). The executive view has always led with a KEV count; it is now reachable from the list. - `GET /v1/scan/{job_id}/remediation` returns the remediation plan for a scan. - The MCP server serves the OAuth authorization server it advertises, and advertises the reachable URL rather than its bind address. - CI runs the CVE accuracy measurements that already existed and had never been wired to a workflow. - **Pre-publish drift gates.** Every stale claim in this release existed because a number or a contract was written once and never recomputed, so each gate derives the truth from the artifact that ships: release-version consistency, discovered structurally across `sdks/`, compose files, k8s manifests and Dockerfiles, where a genuinely independent version must declare itself with a reason and silence fails closed; external-surface freshness for registry and MCP tool/resource/prompt counts; a runtime JSON-RPC check that boots the real MCP server over stdio and compares *names* — not counts — against the wheel's own server card; Postgres schema parity by `pg_dump` diff; and a rendered `docker compose config` contract asserting every service resolves, every `depends_on` names a real service, and every read-only bind source exists. Nothing in CI had ever run `docker compose config` while the deploy docs told operators the stack passes it. Every gate was watched failing on real input before it was made to pass, and six of those failures were live on `main`. - A text equivalent for the graph canvas. Past 200 nodes / 500 edges the page swaps React Flow for a 2D canvas or a WebGL stage, which offered a screen reader only a widget label and a sentence about the draw budget — no node, no relationship, no severity. Both stages now render a census by node and relationship type, the nodes ranked by severity and connection count, and the connections spelled out as sentences, wired to the canvas by `role="img"` and `aria-describedby`. Every truncation is stated rather than applied silently. - **Continue offline with a report file**, on the auth failure screens and the login page. The offline report importer was mounted inside the auth gate, so the feature built for "no working backend" could not render in exactly that situation. It is opt-in, grants no data — every API call behind it fails exactly as it would have — and lives in `sessionStorage`, so it dies with the tab. - `SUPPORT.md`, the one community-health file GitHub surfaces that this repository lacked. The only support routing that existed was in `docs/archive/`, a folder whose own README says it holds material that should not crowd the primary documentation. It promises no new SLA: the only committed response time remains the one `SECURITY.md` already makes. - `GET /v1/graph` reports `completeness.boundary_edges` — the count of edges reaching past the returned node list — so a client cannot mistake the payload for an induced subgraph. - `youcom_search`, an optional MCP tool returning live web and news context alongside the local threat-intel database, contributed by @mouse-value-add. It is the only tool that sends a query to a third party, so it is off unless `YDC_API_KEY` is set, and the credentialed request is pinned to the You.com origin over TLS — `YOUCOM_BASE_URL` cannot redirect the key to another host. This brings the MCP surface to 78 tools. - The release run owns the Docker MCP submission pin. `source.commit` names the commit a release tag points at, so it cannot be written before the tag exists and could not ride along with the version bump; it was a line in SUBMISSION.md asking a human to remember, and had not moved in several releases. The release now opens a PR carrying the tagged SHA. ### Changed - The graph canvas opens at a readable zoom. The roll-up grid was fixed at three columns, turning 106 containers into a portrait tower that `fitView` correctly resolved to 0.16 — roughly 2.6px labels. Column count now follows the estate size; the demo estate opens at 0.40. - The collapsed estate is drawn as a topology rather than a grid of disconnected cards. - ATLAS is an applicability overlay, not 65 failing controls. - TanStack Table upgraded to v9. - A non-zero `scan` exit reads as a verdict rather than a crash. The exit code itself is unchanged; what changed is that the CLI names the gate that fired and links the contract, `scan --help` documents the two gates that fail closed with no flag set — a known-malicious package, and a scan that did not complete — rather than implying exit 1 is reachable only via `--fail-on-*`, and `docs/FIRST_RUN.md` no longer contradicts itself between §1 and §5. The note is suppressed under `--quiet` so CI output stays machine-clean. - Dense lineage graphs open at a readable zoom. The roll-up grid had already been fixed, but the raw lineage branch lays out through dagre, which stacks a wide, shallow DAG into a portrait tower dropped into a landscape canvas — one agent fanning out to 40 servers fit at 0.064. Ranks now reflow into sub-columns when it materially improves the fit, preserving rank order; the same shape opens at 0.380. - The large graph surfaces render in light mode. Both overview renderers painted a fixed `#050505` stage with light labels regardless of theme, so on a light page the largest element on screen was a black rectangle with its own contrast rules. The severity chips on those surfaces had the mirror-image problem. ## [0.99.0] - 2026-08-05 A correctness release. Several defects here caused agent-bom to report *less* than it found, or to report it under the wrong name — the failure mode that looks clean. Read "Security" and "Fixed — wrong or missing output" before upgrading: some numbers you may already be reporting will move. ### Fixed — wrong or missing output - RPM 4.16+ stores its package database as `rpmdb.sqlite`, which is the default on RHEL 9+, UBI9, Fedora 33+, Amazon Linux 2023 and Rocky 9. agent-bom could not read it, so **every one of those images reported zero OS packages and therefore zero OS CVEs** — a clean-looking scan that had not looked. Two independent causes: the header parser required the 8-byte magic that legacy BerkeleyDB records carry and the sqlite blob column does not, and the live RPM parser shelled out to the `rpm` binary with no file fallback (dpkg and apk both already read their database files). A UBI9 image now yields 107 packages and 18 findings where it previously yielded none. - `parse_rpm_packages` ignored its `root` argument while its docstring claimed the database path was derived from it. On a host that *did* have `rpm`, scanning a mounted snapshot reported the **host's** packages as the snapshot's. It no longer consults the host binary for a non-live root. ### Security - `sanitize_env_vars` wrote credential **values** in cleartext for `SSH_KEY`, `ENCRYPTION_KEY`, `PRIVATE_KEY` and `CA_CERT` while the same report listed the variable as an exposed credential. Four separate answers to "is this name a credential" existed; they now share one predicate. - `sanitize_text` redacted an AWS access key **id** and printed the 40-char secret beside it. It also leaked a keyed value in eight shapes — quoted, spaced, JSON, YAML, and base64 `=` padding. - OpenSSH, ENCRYPTED and PGP private keys survived redaction entirely; only PKCS#1/SEC1 labels matched. `OPENSSH` has been `ssh-keygen`'s default since OpenSSH 7.8. - The Docker Hub retention tool followed whatever `next` URL the registry returned **with the Docker Hub bearer token attached**, so a redirected pagination link would have carried the credential off-origin. It now refuses any pagination URL that leaves `hub.docker.com`, bounds the loop, and fails rather than planning deletions against a partial tag list. - The GHCR freshness probe had the same off-origin pagination weakness and is now pinned to `ghcr.io` on the same terms. In the same pass, the surface freshness monitor's tool-count assertion silently switched itself off when `--expected-tool-count` was unset: only the Glama probe derived a fallback, so a bare `python scripts/check_surface_freshness.py` reported a listing fresh without ever checking the count. CI passed the flag, so only humans saw the weaker check. - Configuration was being counted as credentials (`CERTIFICATE_PATH`, `DB_CONNECTION_POOL_SIZE`), and real credentials were being missed (`PGPASSWORD`, `ID_RSA`, `GOOGLE_APPLICATION_CREDENTIALS`, and every plural form). Six copies of that predicate existed across Python, the CLI and the UI; one server reported 25 credentials in the mesh view and 21 in the graph export. ### Breaking - `Package.provenance_attested` is now `None` when the registry could not be reached, rather than `False`. "We could not ask" and "we asked and the answer was no" were indistinguishable in every machine format. The reason is on the new `Package.provenance_status` (`verified` · `not_published` · `not_provenance` · `partial` · `unavailable`). Consumers treating `false` as a negative attestation should now check `provenance_status`. - Compliance framework statuses are now evidence-scoped — `evidence_current` · `review` · `action_required` — replacing the narrative `passing` · `at_risk` · `failing`. The old wording asserted that a mapped vulnerability established framework failure or a regulatory breach; it does not. An explicit non-certification boundary is now carried through CLI JSON, Markdown and the REST responses. agent-bom supplies review evidence; it does not issue an audit, certification, legal or regulatory verdict. The underlying finding-to-control mappings, severities, remediation and freshness are unchanged. ### Fixed — wrong or missing output - **The secret scanner spent its entire file budget on a shadow copy.** It walked with a name-based skip list, and `.` sorts early, so on a checkout containing a gitignored nested worktree the 1000-file cap was consumed before the primary tree was reached. Scanning agent-bom itself reported **177 credential findings that were all in the shadow copy** while the real tree went unscanned — a false negative wearing a false positive's clothes. - Five walkers enumerated the tree themselves rather than going through the shared traversal, and descended into linked worktrees. A worktree is a full second copy of the project, so everything inside it was reported twice. - **Git submodule dependencies were silently dropped from the SBOM.** Nested checkout pruning keyed on the `.git` pointer file, which a linked worktree and a submodule share — but a worktree is a duplicate while a submodule is vendored code that ships. Its manifests and their CVEs disappeared. - **Low-level MCP servers were inventoried under the dispatcher's name.** On the official `fetch` reference server, agent-bom reported a tool called `call_tool` instead of `fetch`. - Django REST `@action` viewset methods, `@transaction.atomic`, `@property` and `@staticmethod` were reported as agent tools. Agent-tool detection existed in four places that disagreed; a test now asserts they cannot drift apart. - **TypeScript `registerTool` matched nothing** — the current API of the official `@modelcontextprotocol/sdk`, and the largest MCP ecosystem. - PCI DSS was never tagged by any scan: its tagger had zero production callers while every other framework was stamped, so a framework counted among the advertised compliance surfaces could only ever report `not_evaluated`. FedRAMP could not match its own catalog (namespaced tags against bare keys). - `scan(package="flask==0.12.2")` returned a false clean over MCP: an unrecognised launcher was forced to `npx`, so a PyPI spec was scanned as npm — 0 packages presented as a complete AI-BOM while `check()` reported 4 CVEs. - Unrated and `none`-severity findings were published to GitHub code scanning as **Medium**. One SARIF document carried five severity tables; four lacked `none` and `unknown` keys and defaulted to `warning`. - A green CIS **PASS** was printed at zero controls evaluated, in three separate renderers, beside "0% pass (0/0 checks)". - A "Clean" badge rendered next to a non-zero vulnerability count, because any advisory without a CVSS vector fell out of the severity histogram while still counting toward the total. - `/v1/proxy/alerts` summarised the page rather than the estate, so `total_alerts` collapsed to the page size and a filtered view described itself as the whole. - A graph trimmed by the node budget serialised byte-identically to the whole estate; a secret scan that hit its file cap reported `total: 0` with no partial marker; `WITH GRANT OPTION` never left the process. - `agent-bom connect` exited 0 on failure and truncated the control plane's remediation guidance mid-word. - `agent-bom scan .` produced nameless assets, because `Path(".").name` is `""`. - CSPM findings never landed on the inventoried asset: one S3 bucket produced three disjoint nodes, breaking finding→asset correlation on every provider. - A partial `[gcp]` extra took down the entire inventory scan instead of degrading: `except ImportError` cannot catch the `AttributeError` a real-but-incomplete SDK raises. - `environment` was populated for Azure and silently `null` for AWS and GCP — only two of roughly twelve emission sites derived it, and the one normalizer that did was Azure-only. GCP compounded it by labelling resources with `labels`, which nothing read. A Snowflake account drill-down returned 1 node of 6, and the canvas silently discarded `api_gateway` nodes. - Three of the sixteen advertised compliance surfaces could not produce evidence at all, and the default signed bundle was unverifiable — found by walking each README persona's journey with real commands rather than by reading code. - The UI's `graphTruncated` banner keyed on `pagination.has_more` alone, which is false on the last page of an already-trimmed estate, so a snapshot cut by the load-time budget rendered with no banner. - Integrity and provenance verdicts reached no machine-readable output at all — console only. They now appear in JSON, CycloneDX, SPDX 2.x/3.0, SARIF, CSV and `/v1/findings`. ### Added - **Kotlin analyzer.** An official `modelcontextprotocol/kotlin-sdk` exists and Kotlin MCP servers were previously invisible. - MCP tool detection for the idioms the official SDKs actually use: Go composite literals, TypeScript `registerTool` and low-level `setRequestHandler`, C# attribute lists, Java `Tool.builder`, PHP `#[McpTool]`, Ruby `define_tool` and `MCP::Tool`, Swift `Tool(name:)`, and Python low-level `list_tools`. - A synthetic enterprise demo estate: **2,068 assets, 6,159 observations across nine log sources, 439 findings on 407 assets, 45 controls**, with the graph growing from 112 to 2,766 nodes. GCP audit collection is deliberately `partial`, so incomplete evidence is shown as incomplete. ### Changed - `/v1/demo-estate/story` went from 1,643 ms with the event loop parked for 1,648 ms to 28 ms warm; a warm read behind an eight-tenant burst went from 16,873 ms to 342 ms. - The SQLite graph store now records planner statistics. Both indexes shared a prefix, and SQLite documents the tie-break without statistics as arbitrary; it had been picking the wrong one for full-snapshot reads. - Release-tag container rebuilds now overlay the current security contract, so refreshing `latest` from an older tag cannot reintroduce a fixed dependency. `cryptography` is pinned to 50.0.0 with platform-specific wheel hashes, and container SARIF paths are normalised before upload. - The registry publish workflow verifies the public catalog's tool count instead of treating an HTTP 202 as freshness, and fails closed on a mismatch. The hosted MCP endpoint now requires a scoped, revocable `bearerToken` rather than being reachable unauthenticated. - `make preflight` now checks the product-metrics snapshot, so drift is caught locally instead of nine minutes into CI. ### Known limitations - The event loop is still parked for roughly 75% of a **cold** demo-story request. The build is GIL-bound; offloading to a thread does not stop it starving the loop, and eliminating it needs process offload or a cheaper build. - `summary.cross_source_correlations` is 3 of 6,148 correlation groups. The demo generator gives each synthetic observation its own trace, so most correlation groups contain a single event. The figure is now reported explicitly rather than left implied by the raw total. - The 2,766-node demo graph has not been verified in a browser. ## [0.98.3] - 2026-08-02 Behaviour changes in this release move numbers you may already be reporting. Read "Changed" before upgrading. ### Breaking - The compliance evidence bundle's canonical signing form changed: the `signature` key is now embedded in the document body and excluded from the hash. External verifiers must drop that key before hashing. Bundles archived before this release remain distinguishable by the field's absence. - `summary.attack_pass`, `summary.attack_warn` and `summary.attack_fail` are removed, replaced by `attack_applicable` and `attack_not_applicable`. MITRE ATT&CK is now an applicability overlay and no longer contributes to any score. - `observed_at` is required on `POST /v1/cloud/runtime-evidence/ingest`. Collectors that omitted it now receive a 422. ### Fixed — evidence the product detected but did not report - A scanned estate with nothing gradeable reported a compliance score of 100 across six surfaces — the REST aggregate, per-framework routes, the MCP tool, the HTML report handed to auditors, the evidence bundle, and the Overview landing page. The score is now derived from the status through one shared scorer, so the two can no longer disagree. - Detective controls (RA-5, CM-8, ID.RA-01, ID.RA-02, DE.CM-09, CIS-02.1/07.1/07.5) were failed by the very scan that evidences them. They now pass on fresh evidence and fail on stale. RA-7 and IR-5, which a scanner cannot observe, are reported as not evaluated rather than failed. - Undateable and future-dated scan evidence scored as fresh; both now fail closed. - Malicious model artifacts were shown in the console but never became findings, so every CI gate passed a pickle implant. They are now `MALICIOUS_MODEL` findings and gate correctly. - Prompt-injection audits of instruction-only files were skipped unless the file also referenced a package, so `agent-bom scan .` missed a malicious `CLAUDE.md`. - A degraded scan reported `coverage_warnings: []` and exited 0. Warnings now reach the written report, and a partial scan exits non-zero. - CISA KEV, EPSS and `kev_due_date` enrichment reached the report; an unavailable KEV feed no longer reads as "not exploited". - Both finding-ingest routes echoed the payload count as `ingested` while payloads sharing a canonical id were correctly deduped on the way in, leaving a client unable to explain why it pushed N and the store holds fewer. The responses now also carry `distinct_findings` and `duplicate_payloads`, and `/v1/findings/bulk` warns when any payload collapsed. ### Fixed — accuracy - Version ranges now fail closed when a bound cannot be compared. Maven qualifier ordering (`.RELEASE`, `.GA`, `SNAPSHOT`) and all three Go pseudo-version forms are implemented, and the GHSA path evaluates the advisory's lower bound rather than only its fix version. - Reachability no longer claims function-level reach from a bare class token. - The posture grade is withheld when vulnerability coverage is incomplete, instead of grading an unscanned estate an A. - Conflicting advisory severities resolve upward rather than by sort order. - Effective-reach scores are clamped to their documented 0–100 range; the highest-risk graph fixture previously emitted 142.8. - Azure private-endpoint inventory now calls the supported `list_by_subscription()` SDK operation; the previous `list_all()` call exists on no stable `azure-mgmt-network` release and left inventory empty. - Azure ML online endpoints and deployments now use the v2 `MLClient`, scoped per workspace, instead of operations absent from the management client. ### Fixed — graph - Roll-ups, drill-downs and every derived view inherit the snapshot's truncation instead of reporting a bounded result as complete. - Credential identity is scoped per server; a shared environment-variable *name* no longer fabricates lateral-movement edges between unrelated agents. - Bottleneck rankings are sampled deterministically and declare their sample, rather than presenting the first 50 nodes in insertion order as fact. - Postgres edge reconciliation is bounded, so a second scan no longer fails to persist and silently freeze the graph. - A finding drill-down no longer substitutes an older graph when the requested scan has no snapshot, and focused investigations no longer show an unrelated global path when no path matches. ### Fixed — control plane and tenancy - Row-level security is forced on the `teams` table and on auto-created monthly partition children, closing a cross-tenant read and delete path. - HTTP- and scheduler-triggered scans run bound to the job's tenant. - Compliance-hub observation partitions are provisioned a year ahead and topped up on every deploy. The previous three-month window could not be extended at runtime and would have broken all current-dated hub ingest permanently. - Malformed requests return a 4xx envelope instead of a bare 500, and validation errors no longer reflect the submitted body. Bulk finding ingest now also rejects a missing or ambiguous JSON content type instead of accepting it. - `agent-bom scan --inventory ` checks that the inventory exists before refreshing the vulnerability database, so a typo fails immediately instead of paying a full cold-start download. - An unreadable or non-UTF8 manifest degrades with a named coverage warning instead of aborting the scan with no artifact. - `HTTP(S)_PROXY` is honoured; it was silently ignored, so pinned egress was not actually pinned. - SIEM delivery rides the hardened delivery client: credentials are redacted, URLs validated, and failures retried into a dead-letter queue. ### Changed - Compliance scores can now move off zero, because controls the scan actually evidenced can pass. An unchanged estate may therefore report a different number than it did on 0.98.2. - Detective-control evidence older than 90 days fails (`AGENT_BOM_COMPLIANCE_DETECTIVE_EVIDENCE_MAX_AGE_DAYS`). - Scope-filtered and free-text findings queries are bounded and report `scope_completeness` when partial, rather than walking the whole tenant. - Read concurrency scales with the worker pool instead of a fixed limit of 8. - The PCI DSS coverage table now reports 12 *sub-requirements* across requirements 2, 6, 8, 11 and 12. It previously read "12 requirements / 12", which implied complete PCI coverage. - The test suite no longer downloads the advisory corpus unless a test opts in with `@pytest.mark.real_vuln_db_sync`, removing accidental network work from ordinary CI runs. - Type-check CI installs the cloud extras and asserts that scanner SDK operations exist, so missing provider methods cannot be hidden by `--ignore-missing-imports`. ## [0.98.2] - 2026-07-27 ### Changed - Operator dashboards use decision-focused findings, activity, remediation, and graph workspaces, and README onboarding uses a compact product-first layout. ### Fixed - Demo scans keep stable agent identities and report their bundled offline advisory evidence without depending on an ambient vulnerability database; optional online transitives remain subject to normal advisory lookup. - Optional runtime enrichment remains read-only, signed runtime audit records retain bounded activity and isolation evidence, and findings expose persisted tenant- and scan-scoped graph reachability when assessed. - Operator views preserve gateway token and cost evidence and distinguish loading, empty, and unavailable state; release builds reject wheels missing the dashboard, schemas, or CSP assets. ## [0.98.1] - 2026-07-26 ### Added - Managed-trial invitation, quota, durable execution, suspension, expiry, and cleanup contracts with PostgreSQL tenant isolation and replay protection. - Personal graph layouts with fit, zoom, pan, reset, auto-layout, edit/lock, keyboard navigation, and locally persisted node positions and viewports. ### Changed - Jobs, finding-class filters, page queries, exports, and totals now use the server contract instead of a client-side sample window. - Pipeline telemetry distinguishes observed, partial, and unavailable evidence; graph summaries report factual freshness, completeness, coverage, and provenance instead of a synthesized quality score. - Findings, remediation, compliance, overview, and investigation use compact task-focused workspaces with shared evidence and progressive disclosure. - README onboarding now starts with a repository scan, keeps synthetic data optional, and presents developer, security, GRC, platform, leadership, and AI/MCP workflows in a compact product story. ### Fixed - Finding-class filters apply before pagination and export, deep links use typed page-query contracts, and missing metrics are not presented as factual zeroes. - Focused graph paths are filtered before layout, relationship labels remain readable at initial fit, and dragged nodes retain their positions without changing relationship endpoints. - Dashboard error boundaries render and report fixed safe messages instead of exposing raw exception text; valid server-generated digests remain available as bounded correlation references. ### Removed - The optional Go runtime tier (`runtime/gateway-relay`, `runtime/event-collector`) is retired. Selecting the Go relay backend also unlocked private-network egress, bypassing the pinned transport's metadata/link-local block for a measured ~8% p95 gain that never met the promote gate; private egress is once again governed solely by an upstream's operator-authored `private_network_approved` bit. The collector's queue-poll mode was never wired and Python already covers it. The relay contract and the `POST /v1/cloud/connections/events/ingest` route are unchanged, so any external collector keeps working. `sdks/go` is unaffected. ## [0.98.0] - 2026-07-24 ### Added - Cloud Connections now persist authoritative account or organization scope, full or continuous scan mode, scan-on-create behavior, and per-connection cadence. Organization-scoped AWS connections fan inventory and CIS evidence across member accounts through short-lived read-only assumed roles; the scheduler and UI expose the effective scope and both cadence gates (#4430, #4431, #4437, #4442, #4459). - Optional Go gateway-relay and posture-event collector contracts. The gateway remains Python-first unless an operator selects the Go relay. The collector ships an authenticated, loopback-first forwarding proof; bounded SQS polling and a published collector image remain explicitly unshipped (#4425, #4427, #4429, #4459). - Public proof surfaces now use the canonical Scan -> Centralize -> Enforce product loop, generated architecture diagrams, and byte-for-byte SVG drift gates in preflight (#4461). ### Changed - Scheduled and manual connection scans share the same full inventory and CIS path. Continuous mode drains configured provider event queues between full scans; it does not replace the full-scan evidence contract (#4431, #4437). - The control-plane scheduler reports the distinct "enabled but no cadence" state. Helm keeps the event collector off unless both an image and the required secret-backed configuration are supplied (#4461). - README and deployment proof now lead with runnable first commands, keep the CLI, Docker, Helm/EKS, gateway, and hosted-demo paths distinct, and avoid treating deployment targets as shipped extensions (#4449, #4460, #4461). ### Fixed - Postgres-hosted demo and control-plane scans persist findings through the migrated workload-evidence schema, password-file/IAM-aware pool, tenant context, grants, and RLS. CI now runs the Postgres contract when scheduler or ingest paths change (#4433, #4455). - Cloud connection scope is authoritative on every scan, scheduler failures are tenant-bound and sanitized, and event-collector helper endpoints require a separate inbound bearer secret before they can forward with the control-plane credential (#4452, #4459). - The packaged API image contains the dashboard again, and the air-gapped Helm profile renders with its intended vulnerability database contract (#4453). - SARIF rules retain advisory descriptions and remediation text, while the CLI normalizes push URLs and publishes a runnable gateway first command (#4456, #4460). - Exposure-path UI labels no longer hide credential or tool hops and remain legible in light and dark themes (#4454). - Replaced the vulnerable transitive brace-expansion dependency line and restored full-suite Ruff compliance found during the release audit (#4458, #4462). ## [0.97.5] - 2026-07-23 ### Fixed - EKS reference install path: co-located baseline `aws_readonly_policy.json`, inline scanner IAM policies, SQLAlchemy-style Postgres URL normalization, Helm writable `/tmp` and UI public seed under restricted PSA, default Kubernetes 1.32, and `abom-eks-lab-ro-*` in scanner `connect_role_arns` (#4421). - UI `postcss` override bumped to 8.5.12 for CVE-2026-45623 (#4420, closes #4419). ## [0.97.4] - 2026-07-22 ### Fixed - Release self-scan gate counts **critical** SARIF results via `security-severity >= 9.0` (`scripts/count_sarif_critical.py`) instead of raw result cardinality. Medium/low first-party `SKILL_RISK` noise no longer aborts publish when the scan exits non-zero for coverage-limited evidence (v0.97.3 tag publish was blocked by this false positive). - Skill auto-discovery skips catalog/index markdown (`README.md` / `index.md` under skills trees) and `site-docs/skills/**` (same as `docs/skills/**`), so first-party docs no longer open medium Skill Risk code-scanning alerts. - Release SARIF upload drops medium/low `SKILL_RISK` rows (keeps high/critical) so GitHub Security is not flooded by first-party instruction hygiene. ## [0.97.3] - 2026-07-22 ### Added - Skill audit feeds the unified Finding stream (`FindingType.SKILL_RISK` / `FindingSource.SKILL`) on CLI and API scans, matches extracted MCP servers against the curated blocklist, and registers a `skill-audit` scanner driver. - Project skill/MCP discovery covers IDE agent trees (`.cursor/{agents,skills,commands}`, `.claude/{skills,agents,commands,rules}`, `.codex/skills`, `.agents/{skills,agents}`) and project MCP settings (`.claude/settings.json`, `.claude/settings.local.json`, `.windsurf/mcp.json`). Auto-discovery skips `tests/fixtures` skill samples so intentional malicious fixtures do not fail project/self-scan severity gates. - Concurrency / failure-model hardening: `asyncio.gather` hot paths use `return_exceptions` with explicit fail-open / fail-closed policy; API scans honor `POST /v1/scan/{id}/cancel` via cooperative checkpoints; online SCA consults `apply_registered_failure_mode("sca-vulnerability")` after retries; operator checklist in `docs/CONCURRENCY_AND_FAILURE_MODEL.md`. - Compose platform stack runs a one-shot `migrate` service before `api` (stamp `init.sql` baselines when needed, then `alembic upgrade head`), matching the Helm migration Job so image upgrades apply Postgres schema changes without a manual Alembic step. - `graph_build_workspace_nodes` / `graph_build_workspace_edges` now ENABLE+FORCE tenant RLS (init.sql + Alembic `20260721_01`); the Postgres workspace backend binds `app.tenant_id` per operation so staging rows cannot cross tenants. - `--repo` / `repo_url` scans attach an optional GitHub trust card (`repo_trust`: stars, contributors, license, language, pushed_at) to the report and stamp an `APPLICATION` (+ root `DIRECTORY`) on the graph; disable with `AGENT_BOM_REPO_TRUST=0` (#4401). - AWS/GCP org discovery emits estate-architecture findings (`ORG-AWS-*` / `ORG-GCP-*`) for standalone / single-account / flat hierarchy / missing SCPs-or-org-policies, with an `architecture` summary promoted to graph misconfigurations and the unified Finding stream (#4402). - Graph builder dual-emits account→resource `OWNS` + `CONTAINS` for cloud inventory and Snowflake object layers so attack-path fusion walks the same hierarchy as estate rollup (#4399, #4400). - Inventory graph API pages packages/jobs with `has_more`; CWPP durable workload-evidence store factory; runtime-evidence ingest uses the scan write rate-limit bucket (#4383–#4385). ### Fixed - Attack-path Path view always lays hops left-to-right (no odd-row snake), so wrapped critical paths no longer draw an inbound arrow into the finding from empty space (#4397). - Graph serve materialises `attack_campaigns` and keeps `attack_path_count` in sync on filtered/attack-path views (#4382). - Agents/servers/packages/resources persist `dimensions.environment` from BOM and resource Environment tags so campaigns and Path filters see env facets (#4399). - Helm scanner, KSPM, and control-plane backup CronJobs fail loud (`jobTemplate.spec.backoffLimit: 0`, `restartPolicy: Never`) so a bad run surfaces as a Failed Job instead of retrying quietly under `OnFailure`. - Hosted POC hardening overlay no longer opts into anonymous API access. `AGENT_BOM_DEMO_ESTATE` / `AGENT_BOM_ALLOW_UNAUTHENTICATED_API` / `AGENT_BOM_NO_AUTH_ROLE=viewer` move to `deploy/docker-compose.demo-override.yml` so customer hosted-poc deploys stay auth-required and `hosted_poc_preflight.py` can pass. Demo redeploy layers the demo overlay and calls `--write-secret` (was a nonexistent `--write-postgres-secret`). - Public demo estate no longer goes empty ~1h after boot: curated `demo-estate-bootstrap` scan jobs are exempt from `AGENT_BOM_API_JOB_TTL` cleanup, bootstrap reseeds when only an empty demo marker remains, and the API cleanup loop self-heals a missing findings spine. Demo redeploy now fails closed when `/v1/findings` total is zero. - Docs honesty: authenticated-hosted overlay matrix points anonymous demo at `demo-override.yml`; PRODUCT_BRIEF marks webhook outbox as shipped; store-backed graph test module docstring matches auto-enable behavior. - README Scan section lists CLI + GitHub Action as peer entry points; Cortex Code skill no longer overclaims agents-for-CVEs (#4398, #4381). ### Changed - CWPP stage-4 honesty: Azure/GCP side-scan capabilities report `executor: contract_only` (discovery + injected-SDK adapters only); runtime evidence ingest + graph persist/investigation loads are documented as wired; Azure/GCP CLI executor and credentialed smoke remain unclaimed (#4158). - CWPP stage-4 (B): CLI `agent-bom cloud runtime-evidence-ingest` and MCP `runtime_evidence_ingest` share the authenticated runtime-evidence door with the REST ingest route (#4158). - CWPP stage-4 (C): JSON / SARIF / HTML exports surface `workload_runtime_evidence` on workload-scoped findings (additive; `clean_workload_assertion` stays false) (#4158). - CWPP stage-4 (D): findings Evidence drawer shows a Workload runtime evidence panel for CWPP/EDR summaries (additive; not a clean-workload assertion) (#4158). - CWPP stage-4 (E): `agent-bom cloud side-scan --provider` refuses Azure/GCP CLI execution (exit 2); `side-scan-capabilities` prints the honest discovery/contract surface (#4158). - Findings carry optional graph FKs (`node_id`, `finding_node_id`, `entity_type`) and attack paths expose `finding_ids` so investigation joins typed estate nodes instead of CVE-label-only anchors; `asset_type` aliases map to `EntityType` without mutating stable asset ids. Evidence redaction keeps the FKs, toxic/CIEM rehydrate preserves them, and graph persist restamps vuln nodes after the throwaway surfacing graph is released. - Findings drawer leads with an Estate node section and deep-links into `/security-graph?node=…&finding=…`; Posture nav is investigation-first and post-login defaults to SecOps investigation home. - README: clean top-nav Live demo link (offline fallback lives under scan/demo body copy), lead with product visuals, and collapse persona / connector / architecture tables under `
`. - Brand shell consistency: CLI serve/gateway startup prints the BOM agent-HUD mark; console/PDF/HTML report titles use `agent-bom scan report`; OpenAPI `/docs` favicon serves `/brand/mark.svg`; login/auth unreachable states show the canonical `BrandLogo` lockup. - Remove private strategy and agent-session audit ledgers from the public tree (`docs/archive/STRATEGIC_AUDIT_*`, `docs/archive/AUDIT.md`, `docs/audits/`); soften large-enterprise procurement phrasing. CI (`scripts/check_public_docs_hygiene.py`) blocks reintroduction. - Compliance UI and docs label framework mappings as a curated evidence helper, not a certification or complete control catalog (dashboard disclaimer + `site-docs/features/compliance.md` / `CONTROL_MAPPING.md` / `ARCHITECTURE.md`). ## [0.97.2] - 2026-07-21 ### Added - `agent-bom attest mcp sign|verify` signs and verifies per-instance MCP scan attestations from a completed scan JSON report (DSSE / dedicated Ed25519 key domain), making the MCP attestation foundation reachable from the CLI (#4336). - `agent-bom auth setup-oidc` guides browser SSO / OIDC setup: validates issuer discovery and emits a copy-paste `AGENT_BOM_OIDC_*` env block (does not change token validation) (#4335). - Hosted-demo freshness is monitored daily via `demo.agent-bom.com/health` in the Deployment Freshness workflow (opens/closes the same supply-chain drift issue used for Railway and Smithery) (#4336). - Helm ships `examples/control-plane-auth-secret.example.yaml` with a per-profile required-key matrix so first-install auth Secrets are documented before `envFrom` (#4337). ### Fixed - Compose self-host first-run bootstrap: secret files are writable by container users (`0644`), postgres init fails loud when the app password is missing, and hosted-poc sets `AGENT_BOM_ALLOW_UNAUTHENTICATED_API=1` so anonymous demo viewers are not blocked by the API-key wall (#4335). - Helm first-install auth posture: profiles document required Secret keys (including multi-replica browser session signing and audit HMAC), Snowflake key mounts use `0440`, and the sqlite demo enables anonymous viewer access (#4337). - MCP server-card `registry_servers` now tracks the bundled registry total (was stale at 427); card `read_only` is false to match write-gated Shield/identity/ ticketing tools; Connections UI and `mcp_server.py` docstring list all 76 tools (#4346). - Glama freshness checker accepts README's "exposes N MCP tools" phrasing (#4346). - `agent-bom audit` rich display fails closed on blocked tool calls even when the log has no `proxy_summary` trailer (aligned with `--json`) (#4346). ### Changed - Drop no-op `dependency-pin-check.yml` and the non-blocking main-only `ci.yml` `agent-bom-scan` job (covered by PR Security Gate + post-merge self-scan) (#4336). - Demo redeploy now triggers on successful `Release` workflow completion (`workflow_run`), builds images before restarting containers to shorten 502 windows, and fails loud when `DEMO_DEPLOY_DIR` is not a git checkout (#4336). - Store-backed UnifiedGraph builds auto-enable above `AGENT_BOM_GRAPH_STORE_BACKED_MIN_ENTITIES` (default 5000) when `AGENT_BOM_GRAPH_STORE_BACKED_BUILD` is unset; explicit off still forces the in-RAM producer. Residual O(N) peak is unchanged — this is a measured reduction, not a strict memory bound (#4336). - README how-it-works diagrams (light/dark) simplified to the three-lane story; live-demo link documents a local `uvx agent-bom scan --demo --offline` fallback (#4336). Blast-radius diagrams remain the GitHub-safe generator art. ## [0.97.1] - 2026-07-21 ### Fixed - Store-backed graph workspaces now resolve mounted Postgres password files and IAM-style credentials through the same hardened connection contract as the API, while keeping secrets out of DSNs (#4330). - Bounded cloud scans, graph workspace provisioning, and advisory/asset identity outputs are included in the released mainline contracts (#4328, #4329). ## [0.97.0] - 2026-07-20 ### Added - Unified Parquet/Iceberg exports now include every unified finding type, keeping lake evidence aligned with JSON, SARIF, CSV, and graph outputs (#4307). - Legacy Postgres audit checkpoints can be reconciled from chain links and historical row counts without weakening tenant RLS (#4305). ### Changed - Auth posture and OIDC bearer decisions now derive from one shared runtime model; JWT-shaped invalid credentials fail closed instead of falling through to API-key lookup (#4309). - Matching now uses strict SemVer prerelease ordering and range-aware alias remediation; Postgres graph persistence remains DML-only, while the store-backed UnifiedGraph seam was proven without changing default runtime wiring (#4303, #4308). ### Fixed - Graph, CSV, and machine exports preserve policy and unified findings, escape untrusted content, and prevent spreadsheet formula injection (#4302). - Auto-seeded connection keys honor `AGENT_BOM_STATE_DIR`; audit rejection logs redact provider details; attack-path migration downgrades remain non-destructive (#4303). ## [0.96.4] - 2026-07-19 ### Added - Live Kubernetes posture is first-class evidence across CLI, API, UI, and MCP, with versioned benchmark provenance and a least-privilege in-cluster deployment path (#4236, #4250). - Authorization evidence now covers AWS Access Advisor and fail-closed Azure/GCP collection, projects into the graph, and reports evidence health for CIEM decisions (#4145, #4171, #4178, #4199). - Read-only DSPM classification now covers production databases and Azure Blob; scheduled findings exports add Azure Blob, GCS, BigQuery, and Databricks destinations (#4090, #4238, #4260). - The framework library adds vendored NIST 800-53 controls and crosswalks, typed ATT&CK/ATLAS mappings, a signing/verification foundation for MCP scan attestations, CWPP lifecycle evidence, and tenant-scoped operator self-posture (#4213, #4217, #4221, #4228, #4230, #4234). - Remediation can file and synchronize tickets through the connect-once ITSM plane without per-action credentials (#4090). ### Changed - Graph persistence, attack-path campaigns, search indexing, and hub ingest/read paths use bounded or streamed working sets with atomic retries and explicit truncation (#4074, #4078, #4091, #4097, #4223, #4231, #4237). - Cloud SDKs move into a dedicated collector image, while maintained Python images install the reviewed `uv.lock` dependency graph with a digest-pinned uv binary (#4256, #4271). - The scan workspace, findings/graph proof, README, CLI walkthrough, and architecture presentation were refreshed against the shipped product surfaces (#4248, #4252, #4270). ### Fixed - Postgres now treats Alembic as schema authority, restores RLS/idempotency/audit-index parity, and decodes native graph JSONB reads correctly (#4110, #4140, #4192, #4232, #4243, #4257). - Scan outcomes, warnings, graph-derived finding categories, keyset pagination, and exports now preserve the same evidence semantics across CLI, API, and hosted paths (#4215, #4233, #4255, #4266, #4267). - Gateway, ClickHouse, and graph pipelines now bound relay buffers, outage queues, reconciliation state, and prior-snapshot work (#4074, #4091, #4240, #4244). - Compliance scoring no longer treats missing evidence as a pass, double-counts subsumed findings, or exposes borrowed benchmark prose (#4249, #4262, #4268). - CI now isolates shared scanner state, distributes tests hermetically, validates the Glama locked-image contract, and scans exact Git event ranges without a pull-request API dependency (#4251, #4254, #4271, #4272). ### Security - IAM conditions, conditional-access evaluation, external DSSE signer trust, and partial identity evidence fail closed instead of silently weakening enforcement (#4080, #4163, #4179, #4182). - Egress validation, delivery boundaries, gateway buffering, audit-chain serialization, and ClickHouse buffering were hardened against rebinding, leakage, forks, and unbounded memory growth (#4185, #4240, #4244, #4245). - File-mounted API keys, trusted-proxy secrets, and confidential OIDC client secrets now share the same startup, middleware, and health posture; weak or unresolved secrets remain unavailable (#4271). ### Removed - **BREAKING:** Retired the legacy `POST /v1/findings/jira` route and its per-action static-token path. Migration: configure a Jira connection once under `/v1/ticketing/connections` (Connections hub in the UI), then file tickets through `POST /v1/ticketing/tickets` — no per-request credentials (#4090). ## [0.96.3] - 2026-07-16 ### Added - Readable-at-scale graph — auto-layout with enforced node separation, clustering, and no pagination (#4005). - Unified Asset Inventory — a page per asset type, correlated to findings and the graph (#4006). - One consolidated Connections hub (Connect + Sources segments) replacing the overlapping Connections/Cloud/Data-sources surfaces (#4008). - Bounded retention plus a default ~90-day time-window filter across findings, snapshots, and graph — the applied window is labeled and overridable, never a silent truncation (#4009). ### Fixed - Skill scanner no longer flags legitimate prohibition/policy language (e.g. an `AGENTS.md` "## Never" section) as malicious — a proximity-clamped prohibition-context guard, with detection of real prompt-injection/bypass directives unchanged (#4050). - Bounded, nested-worktree-aware discovery traversal — project/skill scans no longer recurse into nested VCS worktrees (fixing large-RSS blowups and inflated inventory counts) (#4050). - `serve --no-ui` now actually disables the dashboard (root redirects to `/docs`) instead of still serving it (#4050). - Startup auth-posture log reflects the final effective state, so `--api-key` no longer triggers a misleading transient "No authentication configured" message (#4050). - Index-backed unfiltered effective-reach findings sort — the default findings read is now index-range-scanned instead of a full sort (#4049). - Connections screenshot E2E updated for the consolidated hub (#4048). ### Changed - README: guided self-host/deploy section (incl. the Snowflake SPCS native app) and accuracy fixes; GitHub Pages deploy concurrency hardened (#4043). ## [0.96.2] - 2026-07-15 ### Fixed - Release pipeline: widened the container, self-scan, and published-image gate job timeouts so the release vulnerability scans complete and every publish step runs (no functional change to the product). ## [0.96.1] - 2026-07-15 ### Fixed - Governance NHI audit chain is tenant-scoped across in-memory/SQLite/Postgres backends — cross-tenant actions no longer collide or drop rows, and chain integrity is verified per tenant (#4035). - Helm EKS ingress examples render valid API/UI paths; a structural guard now covers every shipped profile (#4034). - UI accessibility — accessible labels, unique element ids, semantic error-page headings — plus redirects for legacy deep links (#4036). - `/accounts/[ref]` now builds under Next.js static export; added an export-build parity gate to UI CI so release-only build breaks are caught in PRs (#4037). ## [0.96.0] - 2026-07-15 Operator-cockpit release: a premium both-theme design system with every heavy page restyled dense and side-by-side, first-class UIs that bring agents and humans to surface parity, deeper observability→governance correlation, and a governance/security-hardening batch on top of 0.95.0. ### Added - **One canonical finding-list envelope** across every list surface — API, CLI, and MCP now return findings through a single shared shape so pagination, faceting, and totals are identical everywhere (#3993, #3666). - **Coverage lenses as overlapping posture disciplines** — CSPM · ASPM · DSPM · AISPM and vulnerability management render as overlapping lenses over one evidence layer rather than siloed products (#3994, #3996). - **Snowflake estate inventory over REST** — brokered Snowflake connections sweep accounts/warehouses/databases/roles/users and serve them through the inventory REST surface at parity with AWS/Azure/GCP (#3998). - **Per-span trace→attack-path correlation** with opt-in content screening and trace connectors — observability spans map onto graph attack paths (#4000). - **Security-eval scorecard + observe→enforce block-rule proposals** — runtime observations surface as a scorecard and propose enforcement rules before you turn them on (#4002). - **Persisted, versioned governance blueprints with an approval workflow** (#3999); drift-resolve promotes blueprint versions and owner-scoped FinOps budgets (#4003); ABAC device/group/client attributes, scoped delegation tokens, and a served MCP-client-config URL (#4011). - **First-class UIs for AI/ML supply-chain scans, audit export/verify, and the should-I-deploy gate** — agent-only surfaces now have human parity in the dashboard (#4025). - **Operations & Integrations settings** — webhooks, SIEM, threat-intel, and reports management UIs, again at human↔agent parity (#4026). - **OpenVEX ingest for finding triage** (#3985): new `POST /v1/findings/triage/vex/ingest` (and SDK `ingest_finding_triage_vex`) parses an OpenVEX/CycloneDX/CSAF document and applies its `not_affected`/`fixed` statements as tenant-scoped triage suppressions — round-tripping with the existing `GET /v1/findings/triage/vex` export and idempotent on re-ingest. A reusable `agent_bom.vex.parse_vex(dict)` core backs both file (`load_vex`) and in-memory ingest. - **REST-operation count gate** (#3985): `scripts/check-counts.py` now counts REST operations/paths (from the canonical `docs/openapi/v1.json`), route modules, and WebSocket routes, and gates the developer/agent docs that cite the REST surface so they cannot drift from the shipped contract. ### Changed - **Premium design-system foundation** — layered surfaces, both-theme tokens, and dense `DataTable`/`SplitLayout`/`StatStrip` primitives, with every heavy page restyled dense and side-by-side instead of big-card/long-vertical (#4017, #4024). Closes the dashboard-UX and platform-UX epics. - **Flow-ordered, de-duplicated navigation IA** (#4013). - **Graph & DAG canvas scale pass** with in-product actions (#3997); brand/README parity, scan-preset pre-fill, and light-theme token polish (#4001, #3966). - **CycloneDX output upgraded to 1.7** (#3985): `cyclonedx_fmt.py` now emits `specVersion` 1.7 and is validated against the vendored official CycloneDX 1.7 JSON schema in the interop conformance gate. ### Fixed - **Exec severity counts reconcile to one honest source of truth** across posture, overview, and graph (#4023). - **Honest 501 for unsupported Neptune operations** instead of silent/incorrect results (#4018). - **Snowflake CIS benchmark reachable over REST** (#3967): `GET /v1/cloud/snowflake/cis-benchmark` no longer 404s — it runs the real `snowflake_cis_benchmark` and, when the connector/credentials are absent, degrades to the shared HTTP-200 `unavailable` envelope like AWS/Azure/GCP, bringing the REST surface to parity with the CLI/MCP `cis-benchmark --provider snowflake`. - **In-memory compliance-hub sort ceiling guarded** (#3967): the process-local demo backend re-sorts a tenant's whole row list per paged read; past a documented ceiling it now warns once per tenant (steering operators to the SQLite/Postgres backend) instead of degrading silently. No behavior change to results. ### Security - **Trace-connector URL validation** — SSRF guard on outbound trace-connector targets (#4012). - **Blueprint approval four-eyes, tenant-scoped listing, and a Postgres-durable governance audit chain** (#4023, #4018). - **Untrusted VEX log-value sanitization** (#3995). ## [0.95.0] - 2026-07-13 Enterprise auth, cloud-connect, and interop release: browser OIDC SSO, actionable cloud connections, compliance honesty, refreshed dashboard/branding, and a large security-hardening batch on top of 0.94.2. ### Added - **Unified asset inventory (humans + agents)**: new read-only `/v1/inventory/summary`, `/v1/inventory/assets`, and `/v1/inventory/assets/{id}` serve ONE faceted inventory across AI, cloud, identity, secret, and code assets from the shared graph store — counts-by-type → filterable/paginated rows (type/search/severity/environment/provider/source) → asset detail with edges + blast-radius impact. Callable headlessly by agents via API (and MCP), the same evidence the dashboard renders. Brokered **Snowflake** connection scans now sweep accounts/warehouses/databases/roles/users into the graph like AWS/Azure/GCP (#3869). - **Browser OIDC SSO foundation**: `/v1/auth/oidc/login` + `/callback` with authorization-code + PKCE (S256), one-time server-side `state`, an HMAC-sealed PKCE cookie, and ID-token verification through the hardened verifier (#3849). - **Post-scan repo overview**: repo scans surface stats, surface-coverage chips, and a graph deep-link; the API scan path now promotes dependency inventory to `project_inventory` for graph-overlay parity with the CLI (#3848). - **`connect` establishes and verifies a read-only cloud connection**: `agent-bom connect aws|azure|gcp|snowflake` can broker-test credentials locally or register them with a control plane via the same `CloudConnectionCreate` schema the API/UI use (#3842). - **Interop schema-conformance gate**: generated SARIF 2.1.0 / CycloneDX 1.6 / SPDX 2.3 are validated against official schemas with byte-determinism checks in CI (#3826). - **Install-aware upgrade guidance + vuln-DB freshness signals**: `agent-bom upgrade` detects pip/pipx/uv/brew/Docker/binary installs; scans auto-refresh the DB by default (offline-safe) and warn on staleness, with an opt-in `--require-fresh-db` gate (#3838, #3844). - **Postgres IAM auth mode + audit-HMAC key rotation** (#3821). ### Fixed - **Compliance never scores unevaluated controls as pass**: no more "fully compliant / 100" or all-pass framework summaries when nothing was scanned — zero-evidence controls report `not_evaluated` across API, CLI, and UI (#3819). - **Read path off the event loop**: `list_findings` and graph reads no longer block the async loop under load (#3823). - **Severity-filter parity** across in-memory and SQL backends — `info` is no longer conflated with `low` (#3824). - **`scan --no-discover` honors an explicit `--project`** and hard-errors on zero input artifacts instead of exiting 0 clean (#3825). - **Leadership-first Overview**: unbroke the command-center layout (open-issues severity tiles no longer squeezed into an unreadable sliver), grade badge, and tile contrast; rebuilt Top Risks into ranked, correlated risk-chains (CVE → package → MCP/runtime → agent → credential); findings drill-down is now a wider tabbed drawer (Overview / Exposure path / Evidence / Triage) with a visual exposure path; findings lenses renamed to industry terms (Engineering / Compliance); connected-accounts table decluttered into an on-demand detail drawer (#3863). - **Scan entry points consolidated** to one vocabulary — `New Scan` opens the configurator, `Run scan` executes on a scoped target — aligned to the Connect → Scan → Assess workflow, removing duplicate CTAs (#3865). - **Reliable, fully-correlated demo estate**: the seeded demo now populates agents, exposure paths, and non-human identities and restores findings/posture deterministically after restart; a general governance-overlay fix stops managed identities from defaulting to orphaned/never-observed by propagating `owner`/`last_used` (#3866). - **`connect snowflake`** points at the real `scan --snowflake` command (#3846). - **AI-BOM**: canonical model-node identity (no more double-counted models) and real `observes` edges (#3829). - Capability counts reconciled across README/PyPI/docs and enforced in CI (#3827). - SAML SSO counts as a configured auth path (#3831). ### Security - **`POST /v1/scan` local-path jail**: the primary scan endpoint now routes every local-path field (including the previously-unvalidated `external_scan`/`vex`) through the same path-confinement helper + default-off gate the secondary `/scan/*` endpoints use, closing an authenticated arbitrary host-file read; `format`/`min_severity` are enum-constrained and the scan form validates repo URLs client-side (#3864). **Upgrade note:** local filesystem-path scan targets on `POST /v1/scan` are now rejected with `400` by default — set `AGENT_BOM_API_LOCAL_PATH_SCANS=enabled` to allow them (this matches the behavior the secondary `/scan/*` endpoints already enforced). - **OAuth-AS issuer fails closed** on non-loopback listeners; agent-identity JWT now binds `aud`/`iss`; deprovisioning revokes API keys by owner (#3822). - **Signing keys file-first**: OAuth-AS RSA, compliance Ed25519, and proxy signing PEMs resolve from mounted files rather than inline env; `.env.example` leads with IRSA / workload identity (#3820, #3840). - **Postgres app-password no longer persists in cleartext** (init GUC is reset) and is kept out of the DSN; audit-HMAC and connection keys support rotation (#3817, #3821). ### Changed - Refreshed dashboard branding (agent-HUD mark) and README media (#3850, #3813); deduplicated AST scanner primitives; removed an orphaned shim and duplicate scripts (#3828, #3830). ## [0.94.2] - 2026-07-09 Accuracy, security-hardening, and cloud-graph release on top of 0.94.1. ### Added - Cloud graph now rolls up the account → resource `OWNS` hierarchy and materializes live `EXPOSED_TO` network-entry paths, cross-account inventory, and toxic/fusion findings across accounts (evidence-grounded, single-tenant per report). - Opt-in anonymous read-only surface: with `AGENT_BOM_ALLOW_UNAUTHENTICATED_API=1` (default off), credential-less callers are served as the configured `NO_AUTH_ROLE` (default `viewer`) even while API keys are configured, so a public read-only instance can coexist with key-based elevation. ### Fixed - **Reachability accuracy — no false internet exposure**: a permissive or default network ACL no longer fabricates an `EXPOSED_TO` edge for private subnets; network-entry exposure is gated to public subnets (with an internet route), matching the internet-gateway path. - **Reachability accuracy — cross-account trust direction**: inbound assume-role trust edges (`CROSS_ACCOUNT_TRUST` / `TRUSTS`) are no longer walked as outbound lateral pivots, eliminating false cross-account kill-chains from a public foothold. - **Anonymous access is read-only in combined mode**: when credentials are configured, the anonymous fallback is clamped to `viewer` regardless of `NO_AUTH_ROLE`, so it can never grant an unauthenticated caller admin. - **Fresh-deploy demo estate**: the graph database now creates its parent directory, so a seeded demo on a fresh volume (or offline container) no longer crashes to an empty dashboard with "unable to open database file". - Compliance surface no longer duplicates CIS checks across repeated scans of the same cloud; scan-result persistence failures are surfaced instead of silently reported as success. - Snowpark Container Services native-app install blockers (image-tag drift, missing external-access integrations, DDL ordering) and deployment hardening (opt-in data-plane grants, EKS API S3 IRSA, upgrade runbook). ### Changed - Sign-in screen rebuilt into a single, clear API-key flow with real key-provisioning guidance; internal auth-mode strings and reverse-proxy header jargon removed from the default view. - Consolidated weekly dependency, GitHub Action, and UI/SDK toolchain updates. ## [0.94.1] - 2026-07-08 Demo, deployment, and hygiene release on top of 0.94.0 (no scanner-behavior changes). ### Added - Rich multi-cloud showcase estate for the hosted demo — agents, MCP servers, real CVEs (incl. KEV/critical), a typosquat, credential-exposure edges, a multi-hop blast-radius, and CIS checks across AWS/GCP/Azure (#3731). - Demo-mode banner + "connect your cloud" sign-in CTA in the dashboard, funneling public-demo visitors to the authenticated product (#3730). - Authenticated hosted-instance overlay (`deploy/docker-compose.product.yml`) + a copy-pasteable "connect your cloud" runbook for connecting a real cloud read-only (#3729). - IAM/IRSA section in the EKS deployment guide (#3727); Helm chart README (#3734). ### Fixed - Snowflake logo missing in the intake diagram (#3733). ### Changed - Grouped cloud/API tests under `tests/cloud/` and `tests/api/` (#3716, #3718); example AWS account id in a public test fixture (#3732); combined #3675 cleanup follow-ups. ## [0.94.0] - 2026-07-08 Minor release shipping the post-0.93.5 audit/security batch, cloud and runtime hardening, identity/SCIM fixes, CIS fail-closed coverage, and CI evidence improvements for self-hosted control planes. ### Fixed - **git-SHA advisory false positives (offline scan)** — the local `db/lookup` matcher no longer conservatively reports advisories whose only bounds are git commit SHAs (OSS-Fuzz / OSV-2022-* rows) against concrete semver versions; such rows are now classified `uncomparable` rather than `unknown`, so e.g. `pillow==11.0.0` stops drawing `OSV-2022-1074` / `OSV-2022-715`. Genuine semver in-range/past-fix matching and mixed SHA-plus-semver sibling rows are unaffected (#3723). - **Malicious packages missing from CSV/Parquet export** — vuln-less malicious/typosquat packages (synthesized findings) now appear in the CSV and Parquet exports even when CVE findings are present, matching JSON/SARIF, with `is_malicious` and `malicious_reason` populated (#3723). ### Security / audit - **CIS fail-closed** — ~25 checks report ERROR (not PASS) when per-resource reads are denied; strict GRC coverage mode for partial permission denial (#3691, #3695). - **MCP ingest authz** — `ingest_external_scan` gated as a destructive write with admin/scope checks (#3692). - **Shield runtime** — fail-closed defaults, credential redaction in proxy paths, SSRF guard on egress URLs (#3699, #3706). - **SCIM / session** — PATCH remove/add semantics, audit-log viewer RBAC, session logout hardening, auto-bind SCIM subject on API key issuance (#3701, #3705). - **CodeQL / export hygiene** — redacted JSON at formatter boundary; clear-text logging and stack-trace exposure fixes on scan stdout and tenant export (#3717, #3675). - **Audit chain** — signed checkpoint detects tail truncation (#3700). ### Cloud / inventory - **Full cloud coverage** — GCP/AWS pagination, Lambda package fetch, container deep-scan, Key Vault CIS fixes, Lambda on by default (#3634–#3636, #3706). - **Ingest scale** — chunked `reconcile_absent` avoids bind-variable overflow on large batches (#3693). ### Platform / API - **DB-aware `/readyz`** — readiness reflects database connectivity; firewall policy reload fails closed on error (#3707). - **`/v1` router mount** — centralized API versioning foundation without wire contract changes (#3715). - **Env aliases** — canonical deployment/CORS/Vault/ServiceNow env names with regenerated `ENV_VARS.md` (#3713); warn on unparseable bool/int/float env values (#3711). ### Output / CI evidence - **SARIF fingerprints** — `partialFingerprints` for GitHub code-scanning dedup (#3712). - **Malicious findings** — vuln-less malicious packages synthesized end-to-end in exports (#3694). - **SARIF/JSON parity** — finding-count alignment, `--reproducible` timestamps, `/dev/null` exit semantics (#3645). - **Scale-ready HTML** — tabbed, paginated report for large estates (#3637). ### Runtime / graph / data - **Graph performance** — bounded snapshot stats, rollup orphans, deep-offset cap (#3669); drift-as-UI lens (#3649). - **DB maintenance** — generic RANGE-partition retention rollover (#3657); hub read perf fixes (#3654). - **Iceberg / ClickHouse** — catalog export and findings-ingest paths (#3648, #3650). ### MCP / developer experience - **MCP catalog drift guard** — `@mcp.tool` names must match `_SERVER_CARD_TOOLS` set equality (#3675). - **CLI scan UX** — unified terminal sections, deduped CIS output, tiered `--help` behind `--help-all` (#3633, #3672). - **`make preflight`** — local drift gate for OpenAPI, schemas, and release consistency (#3702). ### Docs / deploy - **Doc consolidation** — stage-1 hub structure for duplicate deploy/product clusters (#3704). - **Deployment READMEs** — raw Kubernetes and Snowflake deploy paths (#3720, #3721). - **How-it-works** — canonical deployment matrix and editions page (#3668). ### Also in this release line (since 0.93.5) - Endpoint-agent Phase 0 hardware-backed device identity (#3646). - LLM enrichment harness maturity (#3639). - Swift reachability tail precision (#3656). - Stricter mypy phase 1 for models + core API (#3655). - Test layout: `tests/cloud/`, `tests/api/` grouping (#3716, #3718). ## [0.93.5] - 2026-07-07 Patch release closing the post-#3624 audit queue, hardening demo/hosted POC safety, and documenting public-repo custody boundaries before customer cloud connect. ### Security / audit fixes - **PHP/Swift reachability** — mask comments and string literals before call-site extraction so CVE reachability cannot be over-claimed from prose (#3626). - **GCP Cloud SQL inventory** — paginate `nextPageToken` so public instances past page 1 are not dropped (#3626). - **OAuth AS issuer** — honor `X-Forwarded-Host` only when `AGENT_BOM_TRUST_PROXY_AUTH=1` (#3626). - **Malicious findings parity** — `is_malicious` / `malicious_reason` in CSV, Parquet, and SARIF; `--fail-on-malicious` gates typosquat and dependency confusion packages (#3626). - **Remediation guidance** — suppress downgrade advice when forward fixed version is null (#3626). - **Demo safety** — default `AGENT_BOM_NO_AUTH_ROLE=viewer`; hosted POC overlay sets `AGENT_BOM_DEMO_ESTATE=1` (#3624, #3626). - **Compliance hub in-memory cursor** — align descending `last_seen` tie-break with SQL keyset pagination (#3626). - **Credential ref `/test`** — validate `external_ref` shape and ambient provider probe instead of marking configured without checks (#3626). ### Cloud / inventory hardening - **EBS side-scan** — paginate volume discovery and orphan snapshot sweeps (#3626). - **WAFv2** — paginate `list_web_acls` and `list_resources_for_web_acl` (#3626). - **Trivy CVSS** — honor redhat, amazon, and oracle vendor CVSS sources (#3626). - **Severity policy** — rank `info` above `none` in policy-order comparisons (#3626). - **SCIM deprovision** — revoke rotation replacement keys; match `userName` on `scim_subject_id` (#3624, #3626). ### Docs / positioning - **`docs/PUBLICATION_POLICY.md`** — public OSS vs operator-private custody (secrets, rotation timestamps, hosted bootstrap output). - Remove competitor names from deploy copy and NHI OpenAPI descriptions. - Label `docs/audits/` as historical engineering records. ### Scale / ops - **`scripts/bench/agent_bom_scale_bench.py`** — stdlib scale bench for live API + Postgres smoke (#3626). - Skip `vendor/` trees in Python AST analysis (#3626). ### Also in this release line (since 0.93.0) - UI product-proof screenshot refresh (#3625). - GLM/Zhipu inventory and BYOM quickstart (#3623). - Deploy quickstart, unified install script, and intake diagrams (#3621). ## [0.93.0] - 2026-07-06 Release deepens reachability proof, evidence ingest parity, and the unified `Finding` read path — while hardening API scale, lifecycle, and operator docs for self-hosted control planes. ### Reachability / blast radius - **Multilanguage symbol join** for npm, Go, PyPI (AST), plus Java, Rust, NuGet, Ruby, and Gradle-only Java (conservative regex/manifest proof). - **Symbol reach → triage and VEX**: unreachable symbol evidence feeds `effective_reach` scoring and auto-`not_affected` VEX suggestions (#3577). - **Python symbol reach** exported in JSON/SARIF findings; delta-stream snapshots include symbol-reach material fields (#3571, #3573). - **Advisory context** enrichment (CWE/CVE/CPE) at symbol-join build time (#3576). ### Evidence intake - **SARIF external-scanner ingest** wired into `detect_and_parse` and `agent-bom agents --external-scan` for full scan depth (#3585). - **CSAF and CycloneDX VEX** documents load through `load_vex` alongside OpenVEX (#3586). - **`docs/INGEST_PATHS.md`** documents push vs `--external-scan` tradeoffs, Trivy/Grype/SARIF paths, and VM/registry first-command flows (#3587). ### Finding model / outputs - **Markdown, PDF, and SARIF CVE loops** migrated to the unified `Finding` stream (#3570, #3574, #3578). - **JSON/HTML CVE tables** migrated to `cve_findings()` (#3588). - **Mermaid and graph topology** exports read CVE paths from the unified `Finding` stream (#2918). - **Exposure paths** flow through `Finding` in JSON/HTML/SARIF. - **VEX on Finding stream** with API `external_scan` / `vex` scan parity and SARIF VEX properties (#3589). - **Registry verified badge** in default JSON MCP server rows and CLI dependency tree (#3587). ### API / data plane - **Finding lifecycle** L1–L4: current-state merge, occurrence log, resolve reconcile, SDK ingest (#3470, #3480–#3483, #3465). - **Hub read scale**: keyset pagination, deduped payloads, expression-indexed sorts, gzip/zstd compression (#3515–#3518, #3442, #3454). - **Idempotent bulk ingest** and batch scan caps (#3462, #3474). - **Hub observations partitioning** foundation with retention rollover (#3572). - **Delta-stream connector** for SIEM/data-lake sinks (#3514). - **OIDC JWT replay protection** via jti one-time store (#3561). ### UI / graph - **Findings lifecycle** status in queue; estate roll-up navigation; blast-radius graph overlay; graph lens dock fix (#3551, #3507, #3502, #3505). - **Labeled demo estate** surface lock states, including proxy, gateway, traces, and audit unavailable-state copy (#3467, #3468). ### CLI / headless - **Findings push** CLI wired to hub current-state list (#3549). - **Offline/air-gap** fixes for PyPI check, fleet push, and MCP version (#3556, #3557). ### Docs / positioning - README product-first personas and FinOps lane; internal quick-wins queue moved to `docs/archive/` (#3580, #3587). - Close post-audit hardening tracker **#3242** (corrective arc complete; forward work stays on epic issues). ## [0.92.0] - 2026-07-02 Release hardens the product path from first run to hosted POC: a user can install or run the control plane, connect read-only sources, scan, triage in the queue, inspect graph evidence, export compliance packs, and exercise runtime controls without falling into stale docs or empty UI states. ### Hosted / first-run - **Customer-zero hosted POC loop** with admin-key bootstrap, hosted preflight, smoke script, live brokered connector test actions, and invite-only POC docs. - **Zero-config loopback serve** prints and wires a local development API key so `agent-bom serve` opens a working dashboard without unsafe global auth flags. - **Product editions clarified** around local CLI/CI, self-hosted platform, and gated hosted POC; future managed SaaS plans are not presented as shipped capability. ### UI / operator workflow - **Findings are now an issue queue** with evidence drawer, shared pagination, URL-synced filters, and server-side paging hooks so triage starts from a readable list instead of a dense wall. - **Unified runtime surface** merges proxy and gateway views, adds a runtime live status strip for demos, and keeps fleet quarantine -> gateway deny as a one-click control loop. - **Graph IA cleanup**: one Security Graph entry, discoverable graph lenses in navigation, full-canvas lens switching, older snapshot picker, attack-path queue paging, and WebGL renderer stability for large graphs. - **Offline and empty-state polish** gives every major page actionable next steps when the API, data, or optional connector surface is unavailable. ### Cloud posture / CWPP / DSPM - **Event-driven posture freshness** for AWS, Azure, and GCP: posture can be re-evaluated from provider events with polling/manual freshness surfaced in the Connections UI and docs. - **Multi-cloud side-scan lifecycle** adds provider-neutral workload disk side-scan execution hooks, metadata-only workload findings, redacted secrets, target caps, guaranteed cleanup, and graph promotion of workload-disk resources. - **DSPM classification enters graph risk** with opt-in S3 and GCS sampling, database sample classification, redacted evidence, and low-confidence sampling kept as evidence rather than risk inflation. ### Graph / scale / evidence model - Governance, attack-path, and filtered graph payloads are capped so large estates stay responsive while retaining ranked evidence. - Postgres scale evidence is checked in for release guidance, and large-graph UI tests now focus on stable render proof instead of brittle search drilldown. - Exposure paths now flow through the unified `Finding` projection in Markdown, HTML, SARIF, and JSON outputs, reducing `BlastRadius` formatter drift. ### CLI / MCP - Compact CLI output now has lane branding, a default posture card after scans, paged findings/remediation output, friendlier output-extension checks, and clearer idle compliance semantics. - MCP startup is workflow-first: the server presents curated workflow prompts and demo scripts instead of making users start from the raw tool count. ### Docs / proof / reliability - README, Snowflake connect docs, data-source docs, architecture diagrams, and product proof sections were refreshed for the current surfaces. - CI reliability fixes cover graph E2E stability, access-review date flakes, autodiscovery timeouts, environment leakage between tests, and weekly dependency consolidation. ## [0.91.0] - 2026-06-30 A platform release: AI agents, MCP servers, and their tools become first-class governed assets behind a runtime broker, while the SCA/SBOM/identity/cost depth and the UI all level up. Availability, accuracy, security, and scalability are treated as non-negotiable throughout. ### Runtime broker / gateway - **OAuth 2.1 Authorization Server conformance** for the MCP auth spec — AS metadata (RFC 8414), dynamic client registration (RFC 7591), PKCE authorize/token endpoints, and JWKS — so standard MCP clients auto-authenticate to brokered MCP servers. - **Inline agent-to-agent (A2A) mutual-auth enforcement** at the gateway relay (`off`/`warn`/`enforce`): rejects anonymous / unverified inter-agent and agent→MCP edges. - **Per-tool-call OAuth scope mapping + DLP** on tool args/results: denies insufficient-scope calls and redacts/blocks sensitive data. ### SCA / reachability - **Function-level reachability → CVE** — joins the Python symbol call-graph to advisory affected-symbols, marking findings `function_reachable` vs `package_reachable` for noise reduction. - **`match_confidence_tier` surfaced across SARIF, JSON, and HTML** (not only the unified Finding), with canonical `cve_ids`. - NVD capped-sync now ingests its unsynced tail across runs (no silent CVE drops); CPE inclusive/exclusive version bounds honored exactly; Go pseudo-version bounds; CycloneDX component de-duplication + finding-id scoping. ### SBOM / supply chain - **Sign + attest generated SBOMs** (Ed25519 / HMAC, in-toto / SLSA) via `agent-bom attest`. - **SPDX 2.2 / 2.3 emitter** + per-component checksums. ### Identity / FinOps - **Owner-binding + attribution** on issued agent identities. - **Reconcilable / actual cost rates** (vs static list price) with estimated-vs-reconciled provenance. ### Security hardening - **SSRF blocked in the MCP repo-scan path** (egress validation, no redirect-follow, fail-closed remote bind) and the clone offloaded off the event loop. - Server-authoritative tenant binding on audit ingest; pre-auth global IP rate limiter; X-Forwarded-For spoof fix; identity-keyed MCP rate limiter. - Pickle scanner now scans oversized / disguised pickles (size-gate + memo evasion closed); `--fail-on-severity` fails closed on unknown/none. - DB resilience: SQLite `busy_timeout` + WAL checkpoint; OSV archive streamed to disk (no OOM); KEV/NVD/GHSA wrong-shape + partial-sync guards. ### UI - **Design-system foundation** — Collapsible, Card/Section, StatCard, shared entity icons, vendor logos, and consolidated state primitives. - **Real connections experience** wired to the backend with vendor logos and honest provider readiness. - Declutter + **capability-driven IA** ("Set up" badges, summary surfaces), a **data-driven AI-agent trust stack**, and interaction-state fixes (graph filter soft-lock, provider re-select, URL-as-source-of-truth filters). ### Output - De-duplicated cloud CIS findings in SARIF and HTML; canonical OWASP-MCP/LLM codes from the tool-abuse rules. ## [0.90.0] - 2026-06-30 Native, self-sufficient SCA: distro-confirmed findings are benchmark-grade (e.g. alpine 3.14.2), with an optional NVD CPE candidate tier (review-grade, opt-in) for the long tail OSV and distro feeds do not cover — on top of the multi-account CNAPP estate work below. No external-scanner subprocess is required on the vulnerability path. ### Vulnerability scanning / SCA - **Canonical CVE identity + match-confidence tiers.** `ALPINE-CVE-*` / `DEBIAN-CVE-*` are mapped to their canonical `CVE-*` for cross-tool parity, and every finding now carries a `match_confidence_tier` (`distro_confirmed` > `osv_range` > `osv_ecosystem` > `unfixed_distro` > `nvd_cpe_candidate`). - **NVD incremental sync** (`NVD_API_KEY`) — pulls CVSS/CWE/CPE applicability into the local DB on an incremental, fail-closed checkpoint (the key travels in the `apiKey` header; a failed window is retried, never skipped). - **NVD CPE candidate matching** — a new `cpe_matches` table + matcher map components to `cpe:2.3` applicability ranges to flag non-ecosystem / OS / vendor software OSV and distro feeds miss, with vendor disambiguation for false-positive control. Opt-in via `AGENT_BOM_ENABLE_CPE_MATCH`, surfaced as the review-grade `nvd_cpe_candidate` tier (long-tail only, off by default). - **Parallel OSV batches** with bounded concurrency (`AGENT_BOM_SCANNER_OSV_BATCH_CONCURRENCY`, default 3) and a pipeline-wide 429 backoff so large inventories finish faster without hammering OSV. - **Forced OSV fallback for sparse/EOL distro releases** so end-of-life images do not silently miss advisories. - **Real offline + online scan-accuracy validation** — a deterministic offline three-tier (OSV / distro / CPE) regression net plus live OSV ground-truth and an external-scanner binary-diff harness. Deepens the cloud/CNAPP estate from a single-provider inventory into a multi-account, multi-region, tenant-scale model that rolls up readably in the graph, adds agentless workload (CWPP), audit-trail behavioral, and ASPM application views, and lands a read-only-by-default connect path on every cloud. All cloud access stays read-only and in-account: nothing leaves the customer's account. ### Cloud / CNAPP - **Estate inventory deepened across all three clouds**, with every asset wired into the unified graph: AWS (RDS, DynamoDB, Lambda, EKS, ELB, VPC, KMS, Secrets Manager, CloudFront, ECR, Redshift, SNS/SQS) with multi-region aggregation; Azure (Key Vault, Container Registry, SQL/PostgreSQL/MySQL, AKS, network topology, messaging/cache/disks/App Service, and edge/WAF — App Gateway, Front Door, API Management); GCP (GKE, Cloud Run, Functions, Cloud SQL, VPC, disks, Pub/Sub). - **Tenant-scale account hierarchy as a navigable `CONTAINS` backbone:** AWS Organizations (org / OUs / accounts / SCPs), Azure management-group tree with multi-subscription fan-out, GCP Org → Folders → Projects fan-out, and a Snowflake organization → accounts roll-up. - **Normalized cross-cloud resource model** so AWS, Azure, and GCP assets share one schema and ingest into the graph identically. - **Read-only audit-trail ingestion.** CloudTrail, Azure Activity Log, and GCP Cloud Audit Logs are read via read-only APIs and reduced to behavioral `ACCESSED` / `INVOKED` graph edges (principal → resource, counts and last-seen only — raw events never persist). Opt-in via `AGENT_BOM_AUDIT_TRAIL`. - **Agentless AWS EBS disk side-scan (CWPP).** Snapshots a volume, attaches it to an in-account collector, and reads package/filesystem metadata. Temp snapshots and volumes are cleaned up in a guaranteed `try/finally`, with an orphan sweep recovering after a hard crash; no block data leaves the account. - **Registry-wide container image sweep** across ECR, ACR, and GAR: enumerates repositories and tags via read-only APIs, deduplicates by image digest, scans freshest first, and caps work at `AGENT_BOM_REGISTRY_MAX_IMAGES`. - **Effective-permission foundation:** AWS IAM inline-policy enumeration (not just attached managed policies), Azure RBAC role-assignment inventory with `HAS_PERMISSION` edges, and GCP instance internet-exposure plus IAM privilege classification. - **Cloud data sensitivity classified from resource tags/labels** across AWS, Azure, and GCP. - **Snowflake estate depth:** identity/auth-posture graph with login-anomaly detection (impossible travel, failed-login bursts) and MITRE tagging, object and dependency-lineage graph, exfil graph (shares, external stages, sensitive objects), data-pipeline objects (tasks/streams/pipes), integrations, iceberg and external tables, and governance/activity discovery wired into the scan. - **CIS posture converges into the findings stream and the gate.** Cloud CIS failures now flow into the unified findings stream and the severity gate, drive the verbose posture headline, and render as a grouped, readable report in the terminal and HTML at estate scale. - **Unified cloud-aware scan runs across every configured provider in one command.** Providers are detected by credential source rather than a CLI on `PATH`, native GCP service-account impersonation and Azure subscription auto-derivation give keyless read-only connection, and inventory tolerates partial permissions instead of failing when a role lacks a single grant. ### Graph - **Estate-scale `CONTAINS` roll-up with drill-down.** A 1000+ node estate collapses along its containment tree to a handful of top-level container nodes, each carrying aggregate descendant counts, a by-type breakdown, worst-severity, a per-severity histogram, and internet-exposed / toxic-combination flags propagated from descendants; an attack-path-first view and one-level drill-down are exposed at `GET /v1/graph/rollup`. - **ASPM correlation layer.** AppSec findings (SCA, secrets, IaC, container, SBOM, AI-BOM) are organized around `APPLICATION` nodes via `BELONGS_TO` edges, deduplicated across sources, with per-application risk rolled up. - **Toxic-combination evaluator emits enforceable findings** rather than only annotating the graph. - **New cloud graph edges:** normalized cloud resources ingested as nodes, an internet-exposure edge (public IP → load balancer), and a VM → managed-identity privilege edge (`ASSUMES`). ### Cost / FinOps - **LLM spend fused into the unified graph.** Per-node `cost_usd` / `cost_usd_30d` attributes roll up along `CONTAINS` edges into `subtree_cost_usd`, and nodes that are both high-spend and high-risk are flagged `cost_risk_priority` for cost × exposure triage. ### Identity / NHI - **Lifecycle enforcement for agent identities** with JIT (time-bound) grants. ### Gateway / Runtime - **Policy engine hardened** with fail-closed evaluation, quarantine, conditional access, a plugin surface, and OCSF webhook interop. - **Runtime-observed incidents feed back into the unified graph**, and the gateway consumes graph reachability for pre-emptive blocking. - **Hardened outbound delivery foundation** with OTLP trace emission. ### Remediation - **Advisory remediation foundation with least-privilege-to-apply.** Each fix carries the concrete, minimal IAM actions the operator's own apply role would need, plus optional text-only runbook/Terraform artifacts. Strictly advisory: `applied` and `auto_remediation` are always false — agent-bom recommends, the operator applies. ### AI / MCP security - **Adversarial red-team series:** LLM-harnessed adversarial variant generation, bias/toxicity/hallucination detectors, and an adversarial-coverage governance score with live-target firing. - **Obfuscation-resistant prompt-injection detection** (raises detection on obfuscated payloads from 24% to 100% on the bundled corpus). - **Credentials ranked by exposure even without a CVE**, and **hardware/firmware attestation evidence ingest**. - **Deterministic tool/skills surfaces** so agent-side caching stays stable. ### Scanner - **Incomplete-coverage warnings for end-of-life OS releases.** After distro detection, image/filesystem scans flag any `ecosystem:release` (e.g. `debian:10`, `ubuntu:18.04`, `alpine:v3.x`) that has many OS packages present but (near-)zero advisory rows in the local DB while the data source clearly carries the same distro family at other releases — the signature of an EOL release the feed has dropped. The warning surfaces on the console (a red panel), in the JSON report (`coverage_warnings`, mirrored under `summary.coverage_warnings`), and in the scan-warning count, so a low or zero count for an uncovered release is never read as a clean bill of health. The check is threshold-based and data-source-agnostic; it does not change matching or suppression. ### CLI - **Canonical front-door verbs** (`connect` / `scan` / `graph` / `report` / `up`) as the primary entry path. - **Capability doctor** surfaces every gated feature, its current state, and the unlock path. - **`scan` accepts an optional positional `PATH`**, and scans can be grouped into parent-child batches. - **`agent-bom image` / `agent-bom fs` gained `--ignore FILE`** to suppress named advisories (CVE / GHSA / OSV) from both the report and the `--fail-on-severity` gate. `FILE` may be a flat newline-delimited id list (`#` comments allowed, e.g. `.image-scan-ignore`) or a structured `.agent-bom-ignore.yaml`. ID matching is alias-aware (a GHSA id suppresses its aliased CVE and vice versa). - **`--exclude-unfixable` now applies to the report and gate**, not just SARIF: findings with no available fix are dropped from console/JSON output and from the `--fail-on-severity` gate (an "ignore unfixed" policy). ### CI / Tooling - **Image and filesystem vulnerability gates are self-hosted on agent-bom** (dogfooding). The CI/release/container-rescan/refresh workflows now run `agent-bom image` / `agent-bom fs` (OS-layer dpkg/rpm/apk + application dependencies) and `agent-bom secrets` in place of the previous third-party image/filesystem scanner; no workflow depends on an external scanner. ### API - **REST cloud-scanning endpoints** with MCP write-tool role enforcement. - **Multi-cloud connection brokers.** A stored read-only cloud connection now launches a read-only scan for every provider — AWS (`sts:AssumeRole` with the decrypted ExternalId), Azure (`ClientSecretCredential`, Reader role), GCP (service-account credentials scoped to `cloud-platform.read-only`), and Snowflake (key-pair connection). Provider-specific non-secret parameters are stored in a new `auth_params` column (the single reversible secret stays in the encrypted `external_id`); the secret is decrypted only at broker time and never logged or returned. The background scan scheduler covers all four providers. - **Shared backend contract and selection factory** for control-plane stores. ### Deploy / Packaging - **One-apply EKS platform module** (`deploy/terraform/platform-eks/`) plus a three-tier deploy-anywhere guide ([`docs/DEPLOY_PLATFORM.md`](docs/DEPLOY_PLATFORM.md)). - **Connect-a-cloud Terraform modules** provision one read-only role per cloud (AWS `SecurityAudit`, Azure `Reader`, GCP `roles/viewer` + `iam.securityReviewer`), with keyless federated-credential options and no long-lived keys; CI enforces that the connect modules stay read-only. - **Keyless read-only collectors for EKS / GKE / AKS** via workload identity (IRSA / Azure workload identity / GCP Workload Identity Federation). - **CloudFormation one-click read-only AWS scan** via CodeBuild. ### UI - **Cross-domain overview landing page** and **cloud CIS benchmark drill-down** on the compliance dashboard. ### Changed - **`agents --agent-mode` summarizes the scan payload by default.** The envelope now emits `data_mode: "summary"` with a bounded `data` field — counts (packages by ecosystem, findings/exposure by severity), the top 10 ranked findings and exposure paths, and a summary-level agent inventory — instead of inlining the full per-package provenance dump. For a ~877-package repo the stdout envelope drops from ~27 MB to a few KB so it fits an LLM/automation context window. Pass `--agent-mode-full` (`data_mode: "full"`) or write JSON to disk with `-o report.json --format json` for the complete report; `data.full_report` records how to obtain it. - **Vulnerability cache auto-refreshes** and surfaces a freshness indicator. - Flat (non-graph) outputs prefer canonical findings for consistency with the graph view. - **Demo-mode offline scans resolve a curated bundled advisory set, not the full local DB.** In demo mode an offline scan reports against the bundled demo advisory DB (deterministic, every demo package maps to at least one advisory), which surfaces fewer, curated findings than a real offline scan against the full local vulnerability DB. The active source is labeled in scan output (`bundled demo advisory DB` vs `local vulnerability DB`). Demo screenshots and finding counts therefore differ from real-scan numbers by design — compare like-for-like (real scans use the local/synced DB). ### Fixed - **Fixed agent-mode summary counts.** The envelope `summary.packages` field previously fell through to the full package list; it now reports an integer count. - **Offline coverage gaps now warn instead of discarding real findings** (was a silent false-negative). - **Go `go.mod` block-`require` parsing** no longer emits a phantom package, and **Cargo manifests parse without a lockfile** including target and workspace dependencies. - **Hardcoded-secret findings surface in JSON and SARIF**, not only the console, and **SARIF locates dependency findings at their own ecosystem's manifest**. - **MCP `check` tool** parses pip specifiers and flags errors, reads nonexistent explicit versions as not-clean, and raises a clean error (instead of crashing) on an out-of-sandbox scan path. - **Legacy context graph reads `credential_env_vars`** so lateral-movement analysis is no longer credential-blind, and the **CLI graph export includes the cloud estate** (was local-only). - **Subscription-scoped cloud misconfigurations anchor to their account node** in the graph. - **CLI degrades gracefully on low disk** instead of crashing, and the **cloud inventory summary counts every asset collection**. - **SQLite/Postgres timestamp alignment, dedup, and cost-table DDL** reconciled across the two store backends. - Request models reject unknown fields (`extra=forbid`), and cloud API routes resolve CodeQL info-exposure and log-injection findings. --- ## [0.89.2] - 2026-06-22 Patch release. Supersedes 0.89.1, which was tagged but never published: a second release-workflow startup failure (distinct from the 0.89.0 cause). Same feature set as 0.89.0. ### Fixed - **Release workflow startup failure (reusable-workflow permissions).** The `deploy-mcp-sse` job called a reusable workflow without declaring job-level `permissions`, so it inherited the top-level deny-all default while the called workflow requested `contents: read`. A reusable workflow cannot request more than its caller grants, so GitHub aborted the entire release run at startup. The job now declares `permissions: contents: read`, matching the pattern the `docs-site` reusable call already uses. --- ## [0.89.1] - 2026-06-22 Patch release. Supersedes 0.89.0, which was tagged but never published: a release workflow defect aborted the run at startup before any artifacts were built. ### Fixed - **Release workflow startup failure.** The `self-scan-gate` job referenced a `needs.version-guard` output without declaring `version-guard` in its `needs`, which GitHub rejects at workflow startup — failing the entire release run with no jobs created. The job now declares both dependencies. No product code changed from 0.89.0; this release carries the identical feature set documented below. --- ## [0.89.0] - 2026-06-22 This release extends agent-bom from AI/MCP supply-chain scanning into estate-wide cloud, non-human-identity, and FinOps governance, all converging into the unified security graph. New value is reachable from every surface: CLI, MCP tools, REST API, SDKs, and the dashboard. ### Cloud / CNAPP - **Estate-wide cloud asset inventory.** New AWS, Azure, and GCP inventory scanners enumerate the cloud estate and wire discovered assets into the unified security graph, so cloud resources participate in attack-path and exposure analysis instead of being scanned in isolation. - **Network placement for reachability.** Cloud assets now capture network placement metadata (subnet/exposure context) that feeds reachability analysis. - **Regulatory-regime data classification.** Data stores are classified by regulatory regime rather than a binary sensitive/not-sensitive flag, giving exposure paths jurisdiction-aware severity. - **Crown-jewel and toxic-combination attack paths.** The graph derives crown-jewel exposure and toxic-combination paths, plus pure broad-scope-identity paths, surfaced as first-class attack paths. - **Dormant cloud-inventory, NHI-discovery, cost-center, and credential-expiry scan paths are now wired into the scan pipeline** instead of remaining inert. ### Identity / NHI - **Non-human identity discovery.** agent-bom discovers non-human identities from Okta and Microsoft Entra into the graph, with discovery endpoints and graph wiring. - **NHI usage right-sizing and risk scoring.** Per-identity dormancy/orphan detection, usage right-sizing recommendations, and a per-identity risk score. - **Access-review / recertification campaigns.** NHI access-review and recertification campaign workflows for periodic attestation. - **Credential expiry and rotation governance** across the API and auth layers, surfacing soon-to-expire and unrotated credentials. ### Cost / FinOps - **Cluster-safe Postgres cost store** for multi-replica budget enforcement, so budgets hold across a horizontally scaled control plane. - **LLM spend burn-rate forecasting** with budget-runway projection. - **Cost chargeback / allocation tags** and seasonal anomaly baselines for per-team and per-workload cost attribution. ### Gateway / Runtime - **Unified Gateway Live Feed** consolidating tool-call authorization, DLP, and LLM-call visibility into a single real-time stream. - **Firewall enforcement in the relay** with secure-by-default caller authentication. - **Detection-to-enforcement actions:** quarantined fleet agents are isolated, behavioral-drift incidents and cost-spike anomalies are acted on (not just reported), with policy block reasons redacted in caller-facing responses. - **Break-glass attempts are always audited** and the proxy locks in a fail-closed sandbox posture. ### Supply-chain - **Malicious model-pickle detection** via safe opcode disassembly, flagging dangerous pickle opcodes without executing the artifact. - **Opt-in entropy detection** for novel/unknown secrets beyond fixed patterns. - **Corrected npm caret/tilde semver bounds** for `0.x` ranges in transitive resolution. - **Data-quality confidence** is now computed on native findings. ### AI / MCP security - **Agent->MCP and agent-to-agent (A2A) auth-posture scanning**, including a dedicated governance MCP server. - **New governance and cost capabilities exposed as MCP tools** with surface-count freshness locking, plus unified-Finding suppression / AI-context / reachability fields surfaced in JSON, SARIF, and OCSF output. - **Scan a public repository by URL** (`scan --repo`, `repo_url` MCP argument). ### Infra / DX - **Distributed scan execution** via a Postgres dispatch queue for horizontal scale, and **hardened enterprise tenant boundaries** across the control plane. - **New CLI commands for cost and identity governance** so operators reach the new value without the API. - **Cost-forecast / chargeback and NHI-governance console panels** in the dashboard, with governance lineage colors mapped in the graph. - **Committed OpenAPI contract and codegen-parity Go/Python/TypeScript SDK clients**, with route parity derived from the OpenAPI schema for FastAPI forward-compatibility. - **Multi-hop attack-path fusion** and a graph **evaluation harness** for regression-testing derived paths. - CI test runs are parallelized with pytest-xdist (~12min to ~5min), and Docker builds use a stable Python runtime. ### Security - **Token-only auth for ClickHouse and ServiceNow integrations** with email PII masking. - SCIM posture and misconfiguration messages are sanitized so internal exception detail is not disclosed in the posture surface. - API idempotency keys are bound to their request payloads to prevent cross-payload replay. ### Docs - README, Docker Hub, and PyPI descriptions aligned with current capabilities. - New repo map, clean architecture data-flow diagrams (dark/light), and a start-here guide; root `glama.json` added with improved MCP tool descriptions. --- ## [0.88.6] - 2026-06-05 ### Added - **Agent governance parity controls.** Budget enforcement, signed identity lifecycle audit events, per-tool scopes, JIT/time-bound access, conditional access decisions, and identity/cost/drift UI cockpits are now wired through the control plane, API, MCP tools, tests, and dashboard surfaces. - **CNAPP-style security graph depth.** Exposure paths now include cloud exposure, sensitive data paths, effective-permission escalation, governance decisions, action-level IAM privilege, port-aware network exposure, runtime-observed reachability, and policy/webhook evidence with distinct node and edge semantics. - **Guarded remediation flow.** Remediation can now stage guarded apply operations and draft pull requests with explicit policy, scope, and audit evidence before changes are applied. ### Changed - README and product screenshots now emphasize scan-to-runtime evidence, graph-backed findings, environment/identity/IAM attack paths, readable legends, and contained dashboard visuals. - Dependency automation was consolidated across Python, UI, and GitHub Actions updates so approved dependency PRs land as coherent review units. - The Docker latest refresh workflow now handles API and UI image refresh paths together after a release tag is published. ### Fixed - Upgraded `aiohttp` to address the GitHub security alerts for cross-origin redirects with per-request cookies and unsafe deserialization. - Reworked Railway SSE deployment to run from the trusted release workflow tag instead of checking out `workflow_run` metadata in a privileged deployment context, and refreshed the legacy `agent-bom-scheduled` SARIF category from the current self-scan workflow. - Hardened the UI runtime Docker image by removing build-time package-manager tooling from the final image, clearing the Trivy gate that blocked `agentbom/agent-bom-ui:latest` refresh. - Tightened dashboard and README visual containment so graph labels, path headers, cards, and code samples wrap inside their containers across dark, light, and mobile views. --- ## [0.88.5] - 2026-06-01 ### Added - **Runtime cost attribution (FinOps).** Token counts on ingested OpenTelemetry GenAI spans are priced via an open, operator-tunable cost model (`AGENT_BOM_COST_MODEL_JSON` overrides), persisted per tenant, and exposed as per-agent/model/provider spend with budgets at `GET /v1/observability/costs` and `GET`/`PUT /v1/observability/costs/budget`. New `cost_report` MCP tool. See `docs/COST_MODEL.md`. Metadata only — no prompts or responses are read. - **Agent identity lifecycle.** agent-bom can now issue time-scoped agent identities (`abi_` tokens, stored only as SHA-256 hashes), rotate them with an overlap window, and revoke them: `POST /v1/identities`, `POST /v1/identities/{id}/rotate`, `POST /v1/identities/{id}/revoke`, plus list/detail. The proxy and gateway resolve issued tokens and fail closed on revoked/expired identities. - **Blueprint-drift incidents.** Drift evaluations that report `drift_detected` now persist a durable, deduplicated, tenant-scoped incident, listable at `GET /v1/runtime/drift/incidents` and resolvable at `POST /v1/runtime/drift/incidents/{id}/resolve`. New `drift_incidents` MCP tool. Blueprints become enforced contracts with an audit trail rather than advisory reports. - `agent-bom quickstart --run` executes first-run onboarding end to end: writes the bundled sample stack, runs a graph-persisting scan that populates the local security-graph cockpit, and seeds the secure-by-default gateway baseline policy. The print-only guide remains the default. ### Changed - The multi-MCP gateway relay now enforces control-plane `GatewayPolicy` bindings (`bound_agents`/`bound_agent_types`/`bound_environments`) scoped to the resolved source agent — matching the per-MCP proxy — via a new `gateway serve --policy-bundle` flag. Previously these bindings were enforced only by the proxy. ### Fixed - `agent-bom iac ` now scans a single named file instead of silently returning zero findings (previously only directories were scanned). - Fresh Postgres deployments include the `graph_edges` edge-versioning columns in the `init.sql` baseline and a self-contained Alembic migration, fixing `column "valid_from" does not exist` on migration-only/read-only paths. - The multi-replica tenant-quota guard fails closed (HTTP 503) when its Postgres advisory lock is unavailable under a clustered control plane, instead of silently degrading and overshooting the quota. - Removed committed macOS Finder duplicate files and hardened the duplicate-artifact guard to catch untracked copies in the working tree. --- ## [0.88.4] - 2026-05-26 ### Added - Control-plane evaluation runs with dataset-version linkage, score summaries, trace metadata, and SDK helpers for Python, Go, and TypeScript clients. - TypeScript control-plane client coverage for findings, graph exposure paths, governance decisions, datasets, intel, runtime, and evaluation workflows. - Scope-catalog discovery for auth operators and clearer empty-state messages for graph exposure-path queries. ### Changed - Scan context graph responses now expose the unified graph envelope while preserving the legacy context-graph fields for existing consumers. - Prompt scan results now emit normalized top-level findings with prompt-scan provenance and evidence links instead of remaining only in prompt-specific report data. - MCP registry sync now prefers the official MCP registry API and records defensible source provenance before falling back to legacy sources. ### Fixed - Tenant context handling now requires middleware-populated tenant state instead of route-level default fallbacks, and Postgres RLS bypass events are chained into audit evidence. - First-run Docker Compose profiles now render with the documented example environment file, and release docs clarify cloud posture versus IaC scan lanes. - Weekly dependency and GitHub Actions updates keep the release automation, Docker login, Docker Buildx, CodeQL, and lockfile surfaces current. --- ## [0.88.3] - 2026-05-24 ### Added - Go control-plane SDK, Python SDK ergonomics for positional client payloads, route-parity checks, and richer SDK examples for headless integrations. - Governed threat-intel daily brief inputs, vendor advisory source metadata, package/advisory matching, and documented source boundaries. - Plugin registry status inspection through CLI and API without loading third-party plugin code. - GitHub Action posture outputs and per-finding annotations for downstream CI gates and pull-request review workflows. - SCIM bulk lifecycle endpoint, database evidence fallback lanes, firmware CPE candidate enrichment, persistent issue mappings, and code-topology graph schema types. - Offline HTML export mode that omits external JavaScript assets while keeping static report evidence available. ### Changed - Product and security docs now align around the self-hosted, read-only, pluggable, interoperable trust contract and scoped outbound boundaries. - Shared scan option contracts now prepare the CLI for API/control-plane delegation without changing existing command behavior. ### Fixed - Proxy WebSocket auth now uses the same key store, OIDC, tenant, trusted-proxy, and RBAC enforcement as the REST surface. - Production audit HMAC now requires a persistent key unless ephemeral local mode is explicitly enabled; skills scan and rescan events are chained into the audit log. - Shield write actions now require both admin role and explicit write scope across API and MCP tool paths. - Snowflake tables now define tenant row-access policies, and modern OIDC signing algorithms are accepted. - CSP relaxation is scoped to API docs assets, and dashboard CSP manifests are guarded. - Scan executor lifecycle shutdown is coordinated, graph delta alert scans are optimized, direct MCP package specs scan correctly, and fleet agent list aliases avoid misleading 404s. - Auth rejection, tenant isolation, SDK payload, SCIM bulk, plugin registry, and release-consistency regressions now have targeted coverage. --- ## [0.88.1] - 2026-05-22 ### Fixed - Refreshed the bundled MCP registry catalog before release so registry lookup, marketplace checks, and the release freshness gate use the current server catalog metadata. --- ## [0.88.0] - 2026-05-21 ### Added - Python control-plane client with typed helpers for health, findings, bulk ingest, graph schema, runtime production index, Agent BOM manifest, threat intel sources, advisory lookup, and package matching. - Plugin entry-point registries for `agent_bom.mcp_tools`, `agent_bom.advisory_sources`, and `agent_bom.runtime_emitters`, plus documentation for third-party extension authors. - Runtime blueprints now include a drift evaluation endpoint and MCP tool so operators and agents can compare live runtime posture with an approved role profile without exposing raw prompts, arguments, responses, or credentials. - MCP server mode now exposes read-only runtime posture tools for production index summaries, runtime blueprints, proxy/gateway status, Shield session status, and inter-agent firewall decision dry-runs. - Runtime audit read tools now expose audit query, audit integrity, and proxy alert summaries through MCP for agent-native investigations. - Agentic identity graph edges and runtime identity projections now flow into canonical graph exports and API/UI graph surfaces. - AI visibility manifest signals and dashboard filters now summarize agent, MCP server, tool, owner, risk, freshness, and runtime posture. ### Fixed - Gateway and proxy rate limiting now scope buckets by source agent where identity is available, with tenant-local anonymous fallback and explicit metric labeling. - Scanner accuracy now catches additional Dockerfile risk patterns, training metadata PII, prompt-injection sentinels, and image `--output` JSON file writes. - Graph exports now bound large Mermaid and SVG output by default, preserve full graph counts, include omitted-node summaries, and support full output opt-in. - Agent inventory validation now mirrors the full discovery profile catalog and returns clearer did-you-mean errors for common schema mistakes. - SARIF output now exposes the compliance taxonomy catalog for consumers that read `tool.extensions`, while retaining per-finding taxa. - Product metrics now count the root dashboard page and refreshed MCP tool counts across generated metrics, MCP docs, Docker MCP metadata, and release consistency checks. - Runtime detector documentation and TypeScript SDK detector counts are aligned with the exported runtime package. ### Changed - README, Docker Hub, data-model, deployment, enterprise, and runtime security docs now reflect the v0.88 control-plane story: Python SDK, plugin slots, runtime posture, graph readability, identity projections, and first-run proof. - First-run samples now use intentionally vulnerable package versions that produce real findings, with regression coverage for the expected signal. - The data-model atlas is generated from code and live schema sources so graph entity and relationship counts stay aligned with API/UI/runtime surfaces. --- ## [0.87.1] - 2026-05-18 ### Added - Agent BOM manifest now has a canonical local/tenant inventory contract with a top-level `agent-bom manifest` CLI command, `GET /v1/agent-bom/manifest`, redacted credential references, graph relationships, and a dashboard cockpit for agent/MCP/tool visibility. - Architecture docs now include an AI governance control-plane diagram that ties scans, fleet and endpoint inventory, runtime decisions, threat intel, Agent BOM manifests, graph evidence, and human/agent surfaces together. - **Runtime production index** - added a tenant-scoped `/v1/runtime/production-index` security-observability endpoint for proxy/gateway traffic with tool-call volume, policy decision summaries, active runtime sources, freshness, and explicit retention posture without exposing raw prompts, arguments, responses, or credential values. - Threat-intel lookup and matching surfaces now expose local source freshness, advisory lookup, and package/purl inventory matching over REST and MCP, with canonical CVE/GHSA/OSV/CWE IDs plus evidence links. ### Fixed - Scorecard vulnerability and token-permission hygiene now avoids counting committed parser fixtures as live dependency exposure and scopes selected workflow write tokens to the jobs that require them. - Graph schema now exposes static `node_types` and `edge_types` aliases from the canonical enum taxonomy, so empty graph stores still return the complete type catalog for clients. ### Changed - Root README now serves as a shorter public front door focused on first run, shipped surfaces, deployment links, trust boundaries, and docs handoffs instead of duplicating long deployment and integration reference sections. - **Multi-agent operating contract** - promoted shared engineering, PR style, and release-readiness rules into `.agents/AGENTS.md` so any agent following the [agents.md](https://agents.md) convention (Claude, Codex, Cursor, Continue, Aider, Windsurf) reads the same contract. Added a thin Claude-only `CLAUDE.md` addendum for memory and tool semantics. - **Public documentation positioning** - external scanner ingest is now described by standard format (CycloneDX, SPDX, SARIF, scanner-native JSON) instead of by vendor name across site-docs, examples, ADRs, MCP server metadata, and the boundaries documentation. --- ## [0.87.0] - 2026-05-17 ### Added - **Graph investigation product lane** - shipped bitemporal graph edges, measured benchmark evidence, hardened large-graph overview fallback, API-native `ExposurePath`, toxic-combo graph projection, semantic clusters, renderer-switch contracts, Sigma WebGL overview, light-mode graph token fixes, and optional Neptune backend plumbing (#2541, #2542, #2543, #2544, #2553, #2554, #2555, #2556, #2558, #2562, #2564, #2568). - **Identity-aware investigation flows** - added identity graph taxonomy, AWS IAM enrichment, ExposurePath-first dashboard brief, ExposurePath output parity across JSON/SARIF/Markdown/HTML, and agent-native REST/MCP graph tools for exposure paths and deploy decisions (#2565, #2566, #2567, #2572, #2573, #2574, #2577, #2604). - **Headless control-plane primitives** - added the TypeScript control-plane client, public Python SDK entry points, versioned inventory ingestion, normalized bulk findings ingest, dataset version registry, posture webhook outbox and status API, posture streaming contract docs, and local entitlement metadata hooks (#2601, #2602, #2603, #2606, #2607, #2609, #2611, #2613, #2614). - **IaC and data-stack scanning** - added first-class dbt project security scanning for project metadata, profiles, packages, SQL models/macros, seed files, and dbt CI workflow guardrails (#2615). - **Skills scanner hardening** - decoupled content and provenance verdicts, routed medium behavioral findings to review, added policy-aware CI gates, improved scanner evidence accuracy, and emitted SARIF for skill findings (#2569, #2570, #2575, #2590, #2591, #2592). - **Release proof and positioning** - refreshed product metrics, release proof screenshots, graph release positioning, agent-first product boundaries, product lane boundaries, and the docs/runtime posture-event contract without claiming unshipped Kafka, Kinesis, Pub/Sub, Event Hub, or EventBridge adapters (#2530, #2560, #2563, #2579, #2580, #2588, #2600, #2602, #2605). - **Dependency and release automation updates** - refreshed UI and SDK development dependencies, Python Alpine base image, Docker base-image policy, PyPI native attestations, and Windows endpoint runner pinning (#2520, #2534, #2535, #2536, #2537, #2538, #2539, #2581, #2582, #2583, #2584, #2585). ### Fixed - **SQLite graph upgrade blocker** - fixed legacy local graph DB read-path migrations so existing `graph.db` files add time-versioned edge columns before `/v1/graph*` endpoints query them (#2561). - **Audit chain and runtime integrity** - reconciled runtime AES-CMAC audit verification with the control-plane HMAC audit table and removed raw exception leakage from audit-integrity errors (#2516, #2571). - **CLI and output contract gaps** - made `cryptography` a core dependency for `agent-bom audit`, honored `-o/--output` from wrapper scan commands when CLI profiles are active, preserved auditor enrichment metadata across non-JSON exports, and kept `agent-bom check --agent-mode` machine-readable (#2524, #2525, #2526, #2527, #2540). - **Scanner/runtime data quality** - threaded offline mode into enriched scans, tightened CLI runtime audit gates, aligned canonical IDs across report and graph surfaces, fixed API gateway data audit gaps, and cached agent discovery responses for the API/UI path (#2517, #2518, #2519, #2521, #2522, #2523, #2557). - **Postgres scale evidence workflow** - restored the scheduled Postgres scale evidence workflow environment contract and kept test-only Postgres settings from leaking into unrelated scheduler and Snowflake startup paths (#2616). --- ## [0.86.5] - 2026-05-11 Release-gate patch for the `v0.86.4` train. This release keeps the same product scope and updates the locked `urllib3` dependency to clear the shipping dependency audit before publishing signed artifacts. ### Fixed - **Release dependency audit** - `urllib3` is locked to `2.7.0`, clearing the high-severity findings that blocked the release self-scan gate. --- ## [0.86.4] - 2026-05-11 Patch release for the post-`v0.86.3` release train. This release tightens the CLI contract for automation, refreshes graph/dashboard release evidence, hardens CI retrigger behavior, and closes the final pre-release identity and fixture gaps before tagging. ### Added - **Agent-mode CLI output contract** - `--agent-mode` now gives automation a stable output envelope with bounded confidence fields, token-budget handling, and deterministic error structure (#2479). - **Reusable scan progress streaming hook** - the dashboard can consume the existing scan stream path through shared UI plumbing instead of one-off page code (#2477). ### Fixed - **Release output contracts** - output paths now align with the requested format, stdout behavior is explicit, and JSON output exposes the release posture grade consistently (#2474). - **Native Debian severity fallback** - native image scans derive missing Debian severity data from related canonical CVE records where available (#2473). - **Audit and API guardrails** - audit integrity now fails closed without a configured HMAC key, API rate limits use release-ready defaults, pagination bounds are explicit, and agent identity enforcement requires verifiable JWT policy instead of accepting unsigned identity claims (#2470, #2480). - **Graph and dashboard release polish** - graph labels, defaults, evidence export controls, blast-radius panels, and release screenshot contracts were aligned with the shipped graph surfaces (#2469, #2472, #2475). ### CI - **PR retrigger automation** - ready-PR refresh now avoids the frozen-check loop by using a dedicated automation token path and not disturbing active runs (#2478). --- ## [0.86.3] - 2026-05-08 Patch release for the OpenSSF Scorecard regression and post-`v0.86.2` release readiness fixes. This release keeps the public security posture evidence aligned with the live `main` branch after the scorecard, CI/runtime toolchain, scanner registry, graph serialization, demo remediation, and dependency-refresh work. ### Added - **Scanner driver registry** - scanner driver metadata is now centralized so CLI/API/docs surfaces can reason about scanner capabilities without drifting across hand-maintained lists (#2337). ### Fixed - **OpenSSF Scorecard regression** - tightened scorecard workflow permissions and README positioning so the badge and scorecard run stay aligned with the least-privilege release posture (#2359). - **CI runtime toolchains** - aligned runtime/toolchain setup after main CI failures, including Alpine build prerequisites for native dependencies (#2339, #2348). - **Signed PR refresh automation** - hardened the ready-PR refresh path used to recover approved branches without weakening signed-commit expectations (#2338). - **Demo remediation trust** - tightened demo remediation output so first-run evidence remains reproducible and does not overstate unverified fixes (#2351). - **Self-scan malformed metadata tolerance** - `--self-scan` now skips local distributions with incomplete package metadata instead of crashing on a malformed `.dist-info` entry. - **Proxy sandbox runtime validation** - validates sandbox runtimes by command name so runtime enforcement errors fail on the intended executable boundary (#2349). - **Graph live-edge serialization guard** - added regression coverage for live graph edge serialization so dense graph consumers keep stable relationship payloads (#2358). - **Product path and monorepo scanning copy** - clarified scan/control plane/runtime positioning and monorepo scanning paths in public surfaces (#2357). ### CI - **UI and SDK dependency refresh** - updated Next/React support packages, CodeQL action pins, and TypeScript SDK Node typings with green PR checks and current `main` CI evidence (#2330, #2331, #2340, #2341, #2342, #2343, #2346, #2360). --- ## [0.86.2] - 2026-05-07 Audit-readiness patch for the live dashboard/API release pass. This release closes the scan-contract, graph-serialization, gateway-transport, CI refresh, image tarball, API extras, MCP/HTTP contract, and gateway NetworkPolicy hardening items validated after `v0.86.1`. ### Added - **Airgap image tarball entry point** - `agent-bom image --tar ` now scans local OCI/Docker tarballs without requiring a Docker daemon or registry pull path (#2327). - **MCP-to-HTTP scan contract coverage** - regression coverage now asserts MCP scan output shape stays aligned with the HTTP scan path for shared scan internals (#2326). - **Gateway component NetworkPolicy** - Helm now renders a gateway-specific default-deny egress policy with explicit DNS/upstream allowlist hooks instead of relying only on global policy coverage (#2328). ### Fixed - **Strict scan request validation** - direct and source-triggered scan requests now reject unknown fields with 422 errors instead of silently dropping typoed inputs (#2319). - **Dashboard protected-view UX** - protected graph/dashboard views now turn empty API-key and browser authorization-header failures into sign-in/forbidden states instead of raw DOM exceptions (#2319). - **Graph API serialization readiness** - graph edges, attack paths, node detail relationships, diff metadata, and path query aliases now serialize consistently for dense graph consumers (#2323). - **Gateway upstream transport guardrails** - SSE upstreams are rejected with an explicit configuration error instead of being relayed through an incompatible POST path; streamable HTTP upstreams keep working (#2322). - **SQLite graph schema initialization race** - graph schema marker initialization is idempotent, preventing concurrent initializer failures in CI and tenant graph persistence (#2320). - **First-run sample flag alias** - the first-run sample CLI now accepts the documented target alias consistently (#2321). - **API extras diagnostics** - API startup dependency checks now report the missing import details instead of over-collapsing into a misleading extras message (#2325). - **Ready-PR refresh loop** - stranded approved PRs now have a safer refresh path so branch updates do not freeze behind stale checks (#2324). --- ## [0.86.1] – 2026-05-06 Patch release alignment after the `v0.86.0` tag failed before publish at the MCP registry serialization gate. ### Fixed - **MCP registry release serialization** — reformatted the bundled registry with the canonical Unicode-preserving serializer so the release gate no longer mutates `src/agent_bom/mcp_registry.json` at tag time. - **Pre-tag registry serialization guard** — `scripts/check_release_consistency.py` now verifies MCP registry serialization stability during normal CI/pre-release checks, preventing this class of failure from reaching the tag workflow again. - **Short-description limit guard** — release consistency now enforces the 100-character publish limit for the package short description before release workflows reach registry publication. --- ## [0.86.0] – 2026-05-03 AI-infra and supply-chain breadth release: ATLAS catalog wired through to dashboard, Snowflake Native App Phases 1–3 with DCM as a first-class IaC type, GPU cloud + driver/firmware coverage (AMD/Intel/NVIDIA, Lambda Labs / RunPod / Vast.ai / Crusoe / Nebius), Compliance Hub closed end-to-end (#1044), plus two new content scanners (SPDX licenses, dataset PII/PHI). ### Added - **Compliance Hub series** — `compliance_hub.py` engine plus four ingestion adapters (SARIF / CycloneDX / CSV / JSON) and four hub API endpoints (`POST /v1/compliance/ingest`, `GET /v1/compliance/hub/findings`, `GET /v1/compliance/hub/posture`, `DELETE /v1/compliance/hub/findings`) so external scanner output lands in the same per-tenant posture surface as native scans. Closes #1044 (#2200, #2201, #2203, #2204). - **Durable Compliance Hub backends** — SQLite and Postgres stores back the hub with tenant-scoped persistence and reserved-namespace tenant validation, replacing the in-memory placeholder (#2205). - **MITRE ATLAS catalog refresh** — `atlas_fetch.py` pulls from `mitre-atlas/atlas-data` so the catalog stays current; CI guards against drift (#2215). - **IaC → ATLAS mapping for AI infra** — Terraform / Helm / K8s findings annotate the matching ATLAS technique IDs so dashboards can pivot from infra control gaps to adversary technique coverage (#2216). - **ATLAS coverage tile on dashboard** — `/compliance` page surfaces the bundled MITRE ATLAS catalog (version, curated-vs-upstream technique count, last-updated) so users can verify the catalog they are matching against (#2217). - **Snowflake Native App Phase 1** — manifest, customer-approved access policy, DCM module, and tenancy boundary (#2210, #2220). - **Snowflake Native App Phase 2** — Snowpark stored procedure that materialises Compliance Hub posture inside the customer's Snowflake account; results never leave tenant boundary (#2226). - **Snowflake Native App Phase 3** — SPCS-hosted Next.js UI with service-role binding so customers run the full agent-bom dashboard inside Snowpark Container Services (#2227). - **Snowflake DCM as first-class IaC type** — DCM scripts get a dedicated parser and finding namespace alongside Terraform/Helm/K8s/CFN/Pulumi (#2218, #2222). - **DCM fullstack wiring + IAM-to-agent graph edges** — DCM resources flow through the scan pipeline into the graph; IAM principals get a `MANAGES` edge to derived agents (#2233). - **IaC scanner context — two-gate dispatch, capability verdicts, deployment-aware** — scanners now carry deployment context so the verdict reflects "what this manifest actually deploys" rather than syntactic posture (#2223). - **AMD advisory scanner** — AMD PSIRT advisory ingestion + GPU driver CVE mapping + K8s GPU compound rules (#2224). - **AMD PSIRT live-feed fetcher** — keeps AMD advisory data fresh; falls back to a checked-in static seed if the upstream feed is unreachable (#2230). - **AMD/Intel driver CVE gates + Intel advisory feed + K8S-036** — per-node driver checks for both vendors plus a K8s rule (`K8S-036`) for `nvidia-device-plugin` RBAC scope (#2232). - **Intel i915/xe driver CVE gate** — per-node check for CVE-2023-22655 / CVE-2023-25546; reads `/sys/module/i915/version` or `/sys/module/xe/version` via `kubectl exec`, falls back to `uname -r` (#2236). - **NVIDIA DGX/HGX firmware + BMC advisories** — `firmware_advisory.py` ships a 6-CVE NVIDIA CSAF seed (3× H100 BMC/CLI critical/high, DGX A100 SBIOS, ConnectX-6 DoS, DGX Station A100 OOB write); per-node product mapping via GPU-model labels; surfaces through `GpuInfraReport.firmware_findings` and `risk_summary.firmware_cve_count` (#2236). - **Container image SBOM (RunPod / Vast.ai)** — `container_sbom.py` fetches Docker Hub registry v2 metadata (manifest digest, config labels, layer size). Emits `UNPINNED_TAG`, `NO_SBOM_ATTESTATION`, `STALE_IMAGE` (>180d), `MISSING_PROVENANCE` findings; offline-safe and graceful on token/manifest failures; per-process `lru_cache` so duplicate pods share one Docker Hub round-trip (#2236). - **GPU cloud provider discovery** — Lambda Labs, RunPod, Vast.ai, and Crusoe added to the cloud catalog; agents emerge with `cloud_origin.provider` set to the right vendor (#2229). - **Nebius InfiniBand training job discovery** — Nebius training jobs and their InfiniBand fabric scope are discovered as agents (#2231). - **SPDX license file scanner** — detects `LICENSE` / `COPYING` files and SPDX source-header markers across the inventory; results feed the existing license posture surface (#2234). - **Dataset PII/PHI content scanner** — CSV / JSON / JSONL content scanner that flags datasets containing PII/PHI columns or values (#2235). - **Identity and naming contract hardening** — locks the platform identity / canonical-name vocabulary so downstream surfaces stop drifting (#2207). - **`summary.unique_packages` field on JSON output** — disambiguates occurrence count from the deduplicated package count so dashboards stop double-counting transitive duplicates (#2199). - **`summary.total_packages` semantics clarified** — documented as occurrence-shaped to match the existing wire format and pair with `unique_packages` (#2199). ### Fixed - **`--self-scan` walks the active venv** — `_build_self_scan_inventory` now uses `importlib.metadata.distributions()` so transitive deps appear in the inventory (#2197). - **Dashboard splash kind classification on `/compliance` and `/vulns`** — auth and forbidden errors now render distinct copy instead of the generic "Cannot connect" splash (#2199). - **v0.85.0 multi-persona audit P1 items** — close-out doc fixes for the persona-targeted README/docs surfaces flagged in the v0.85.0 review (#2208). - **Compliance Hub posture aggregates all 15 frameworks** — posture endpoint no longer truncates at the first frameworks; CHANGELOG synced in the same PR to match shipped behaviour (#2221). - **Docker Hub short description trimmed to 100-char API limit** — release publish step no longer 422s on the description sync (#2225). ### Documentation - **`--self-scan` flag reference** added to the CLI docs (#2202). - **Compliance SVG framework alignment** with `COMPLIANCE_FRAMEWORKS` so the diagram and code list never drift (#2206). - **Policy-precedence + runtime-reference consolidation** — single source of truth for how runtime gating, firewall, and proxy policies interact (#2209). ### CI - **DCM scanner self-check** — meta-recursive job runs the DCM scanner against the agent-bom-shipped DCM manifests on every PR (#2228). --- ## [0.85.0] – 2026-05-02 Two new product surfaces (inter-agent firewall + per-run discovery envelope) plus four audit-driven defect fixes from the v0.84.6 hands-on review. ### Added - **Inter-agent firewall** — tenant-scoped policy engine for agent → agent delegation. Pairwise + role-tag rules with `allow` / `deny` / `warn-only` decisions, dry-run mode for safe rollouts, hot-reloadable policy file. Decisions emit through the existing `/v1/proxy/audit` HMAC-chained audit relay. CLI: `agent-bom firewall validate / list / check`. Runtime card on the gateway dashboard tab. Issue #982 closed by #2188 / #2189 / #2190 / #2191. - **Per-run discovery envelope** (#2083) — every discovered Agent now carries a trust contract recording the actual scan mode, explicit scope, IAM/API permissions exercised, and redaction posture for that run. Locked enums (`scan_mode`, `redaction_status`), schema-versioned (`envelope_version: 1`), surfaced through the existing `/v1/agents` API and a new `DiscoveryEnvelopeCard` on agent detail with a data-residency note. Wired on AWS, GCP, Azure, CoreWeave, Nebius, Snowflake, Databricks, MLflow, W&B, HuggingFace, OpenAI, and Ollama. Cross-provider least-privilege + redaction lock-in matrix tests every catalog entry against an explicit read-only verb allowlist (`Get` / `List` / `Describe` / `Search` / `Read` / `Select` / `View` / `Retrieve` / `Show` / `Fetch` / `Scan` / `watch` / `GET` / `HEAD` / `OPTIONS`). Issue #2083 closed by #2192 / #2193 / #2194 / #2195. - **Diagrams alignment** — engine-internals and compliance SVGs realigned to canonical product counts (15 ecosystems, 14 + AISVS frameworks, 29 MCP clients, 36 MCP server tools, 26 output formats, 419 test files); OpenClaw / ClawHub framed as distribution surfaces in `integrations/openclaw/README.md`. Issue #2150 closed by #2187. ### Fixed - **SCIM DELETE removes users from default listing** (P1 IdP-blocker, audit #2196) — `deactivate_user` flips `active=False` and bulk `list_users` now excludes deactivated users, matching Okta/Azure AD deprovisioning expectations. Precise lookups by `userName` / `externalId` / `id` keep finding deactivated users so admins can verify the deactivation landed; `?filter=active eq ` is the new admin-audit primitive. Re-creating a deprovisioned `userName` still 409s. - **`--allow-insecure-no-auth` no longer silently overridden by SCIM bearer** (P2 audit #2196) — `_enforce_auth_defaults` recognises `AGENT_BOM_SCIM_BEARER_TOKEN` as a valid auth path. When the flag is set together with any auth method, a yellow warning to stderr names the active method instead of pretending the flag disabled auth. - **Dashboard "Cannot connect" splash distinguishes auth from network errors** (P2 audit #2196) — `ApiOfflineState` takes a `kind: "network" | "auth" | "forbidden"` prop; pages classify thrown errors via `ApiAuthError` / `ApiForbiddenError`. Auth/forbidden cases get distinct copy ("Sign in to view the dashboard" / "This account doesn't have access"). - **`POST /v1/auth/keys/{id}/rotate` accepts empty body** (P3 audit #2196) — body now optional; defaults applied silently for missing or `{}` payloads. - **Strict MCP tool argument contract** (P1 audit #2197) — every registered tool's JSON schema now sets `additionalProperties: false`, and a runtime guard at the tool-manager call boundary rejects calls with unknown argument keys before FastMCP's Pydantic validation silently drops them. Pre-fix, AI agents passing typo args (`Version` capital, `frob`, etc.) got false-clean verdicts on the pre-install gate. - **Skill trust verdict split into provenance + content axes** (P1 audit #2197) — `TrustAssessmentResult` now carries `provenance_verdict` (signed? install metadata complete? source URL?) and `content_verdict` (behavioural risk signals from the audit) alongside the legacy `verdict`. Pre-fix, three legitimate cybersecurity playbooks were marked `malicious` purely because they were unsigned and lacked a frontmatter `source:` URL despite zero detected risk signals (~80% false-positive rate on real security skill trees). - **`--self-scan` walks every venv distribution** (P2 audit #2197) — `_build_self_scan_inventory` now uses `importlib.metadata.distributions()` so transitive deps appear in the inventory. Pre-fix, only ~23 declared deps were scanned vs ~66 actually installed. - **Proxy stderr sandbox warning is single-emission** (P3 audit #2197) — the duplicated `sys.stderr.write(warning)` is dropped; `logger.warning(warning)` is the single source. The structured `mcp_execution_posture` audit event still carries the same posture detail in machine-readable form. ### Documentation - New `docs/AGENT_FIREWALL.md` — schema reference, gateway integration, proxy fast-path, dashboard overlay, 4-PR roadmap. - New `docs/DISCOVERY_ENVELOPE.md` — schema reference, locked vocabulary, producers table, API + UI surface, lock-in matrix. --- ## [0.84.6] – 2026-05-02 ### Added - **CLI startup banner** — running `agent-bom` with no subcommand now renders a branded banner with three quick-start commands and a docs pointer (#2181). - **Verdict-led compact summary** — `agent-bom scan` ends with a one-line posture verdict plus inventory; the previous detailed configuration-posture panel is preserved behind `--verbose` (#2184). - **Severity-coloured scan closer** — the trailing line now renders a coloured `Scan complete — N critical · N high · …` breakdown instead of a generic finding count (#2181). - **Findings header label** — when priority filtering hides rows, the table header reports `Findings (X of Y shown · Z hidden)` so the elision is visible (#2181). ### Fixed - **Severity closer rendered empty on Python 3.13** — `Severity(str, Enum)` `str()` semantics changed; the closer now reads `Severity.value` so the breakdown renders content on every supported Python (#2185). - **npm SemVer pre-release tag handling** — `compare_version_order` now strips `-canary.N`, `-beta.N`, `-rc.N`, etc. before PEP 440 parsing so npm pre-releases no longer fall through to the conservative "affected" verdict (e.g. CVE-2023-46298 false positive on `next@16.2.4-canary.13`) (#2182). - **Stacked progress lines under interleaved log warnings** — scanner warnings now flow through Rich during the progress block, so spinners stop double-rendering when GHSA/OSV emit warnings mid-scan (#2183). - **OSV-first GHSA UX** — the "GITHUB_TOKEN not set" / "limited to N unauthenticated lookups" notes are now informational only and no longer surface as scan warnings; OSV mirrors GHSA within ~24h, so the unauthenticated path is the default for typical use and a `GITHUB_TOKEN` is only needed for fresh-CVE turnaround under 24h (#2181). --- ## [0.84.5] – 2026-05-01 ### Added - **MCP package version provenance** — packages now carry canonical `version_source` and `confidence` metadata, structured evidence, version conflicts, and resolved-version timestamps across scanner data, graph/API outputs, SARIF, SBOM formats, attack-flow exports, SVG graph output, and dashboard surfaces. - **Floating MCP command resolution evidence** — `npx` and `uvx` package detection now upgrades floating commands from low-confidence registry fallback to higher-confidence local tool-cache evidence when downloaded package metadata is available. ### Fixed - **Focused CLI flag parity** — `agent-bom secrets` and `agent-bom skills scan` now accept `--no-color`, `--log-json`, and `--log-file` consistently with the rest of the CLI. - **Version provenance evidence redaction** — package-version evidence now sanitizes local package paths before findings are emitted. - **Skills quiet output** — `agent-bom skills scan --quiet` suppresses extra prose without dropping the findings table. --- ## [0.84.4] – 2026-05-01 ### Fixed - **Deterministic release registry gate** — tag workflows now verify committed registry freshness and local JSON serialization stability without running live registry syncs against moving external catalogs. - **Patch release alignment** — bumped release surfaces from the failed `v0.84.3` tag to `v0.84.4` after the registry gate proved the live-sync check was nondeterministic. --- ## [0.84.3] – 2026-05-01 ### Fixed - **Release docs deployment guard** — GitHub Pages deployment now only runs from `refs/heads/main`, so tag-triggered release builds can verify docs without entering the protected Pages environment. - **Patch release alignment** — bumped release surfaces from the cancelled `v0.84.2` tag to `v0.84.3` after the tag workflow was cancelled before package publication. --- ## [0.84.2] – 2026-05-01 ### Fixed - **Release tag gates** — reusable docs builds now skip GitHub Pages deployment when invoked by the tag release workflow with `deploy: false`, preventing protected Pages environments from blocking package publication. - **MCP registry sync determinism** — all bundled registry writers now share Unicode-preserving JSON serialization, preventing release-gate churn from rewriting capped descriptions between literal `…` and escaped `\u2026`. - **Bundled registry freshness** — refreshed the committed MCP registry to 658 servers so the strict `sync-all` release gate can pass without weakening freshness checks. --- ## [0.84.1] – 2026-05-01 ### Fixed - **Gateway auth and GHSA rate-limit hardening** — gateway API-key verification now fails closed on key-store errors, and unauthenticated GHSA enrichment is capped with upfront warnings so CLI/API/dashboard scans do not pause for long GitHub advisory backoff storms. - **Extension registry safety** — the extension entry-point registry is documented and explicit, keeping plugin-style imports opt-in instead of silently importing installed package code during security scans. - **CLI documentation and exit-code alignment** — grouped CLI docs now match the 30+ command surface, usage errors consistently return exit code 2, and release checks guard future CLI reference drift. - **Graph export parity** — CLI Cytoscape, Graph HTML, Mermaid, GraphML, Cypher, and API graph paths now surface conservative credential → tool `reaches_tool` evidence consistently. - **Dashboard scan polling** — the scan detail UI now polls a lightweight status endpoint during async scans and fetches the full result only once at completion, avoiding repeated multi-MB `/v1/scan/{id}` payloads. - **CLI error contracts** — listener ports now reject privileged or invalid values before socket bind, and malformed inventory, VEX, policy, and ignore files fail loudly with actionable parser messages instead of raw tracebacks or silent skips. - **Pre-release output polish** — clean scans now describe config-posture gaps without contradicting `SECURITY POSTURE: CLEAN`, project-scoped agents render with human-readable labels, and CSV inventory ingestion logs skipped empty package rows. - **Delta gate artifact consistency** — delta-mode filtering now happens before report rendering so JSON/SARIF artifacts and CI exit gates reflect the same new-only finding set. - **UI E2E production parity** — Playwright now runs against a staged standalone bundle that mirrors the container runtime, preventing hydration checks from passing only in dev mode. - **Release registry freshness** — the bundled MCP registry is refreshed for the patch release, release gates now enforce freshness before tagging, and registry descriptions are capped at 100 characters across sync paths to protect catalog/UI consumers. --- ## [0.84.0] – 2026-04-30 ### Added - **Graph capability reachability** — graph construction now emits `EXPLOITABLE_VIA` edges from affected packages/vulnerabilities to reachable MCP tool capability nodes, closing the package → MCP server → tool → agent attack-path chain for graph consumers. - **Cloud discovery and ingest skills** — bundled skills now cover Azure, GCP, Snowflake, and pushed-inventory ingest workflows alongside the existing AWS discovery path, with the same guardrail contract, provenance requirements, and read-only defaults. - **MCP server resources, prompts, and capability metadata** — the server card now advertises 36 read-only tools, 6 resources, 6 workflow prompts, and machine-readable capability classes so agents can choose the right workflow without guessing. ### Changed - **Human reports and graph risk state** — Markdown, HTML, compact console output, and graph nodes now render unified non-CVE findings such as MCP blocklist hits with matching severity, evidence, remediation, and blocked/warning state. - **Snowflake and self-hosted deployment path** — Snowflake POV docs, EKS deployment profile, BYO Postgres guidance, and deployment navigation were tightened around the current operator-pull and customer-managed data-store model. - **MCP documentation and metrics alignment** — MCP docs, server-card descriptions, product metrics, Glama/MCP registry manifests, Docker/Helm references, OpenClaw skill metadata, and README release refs now align to the v0.84.0 surface. ### Fixed - **Bundled skill contract enforcement** — skill guardrail metadata is now regression-tested so new skills must declare credential handling, data flow, file access, network endpoints, invocation policy, and verification posture. - **Posture headline calibration** — compact output no longer pairs high/critical policy findings with a misleading strong/clean posture headline. - **Release-surface drift** — package metadata, Helm chart/app versions, image pins, registry manifests, skill versions, and verification docs were bumped together for the v0.84.0 release. --- ## [0.83.4] – 2026-04-30 ### Added - **Snowflake scope-zero operator-pull adapter** — Snowflake now joins AWS, Azure, and GCP as a first-class operator-pushed inventory path, letting teams collect Cortex/Snowpark/Snowflake AI inventory inside their own boundary and explicitly decide whether to hand the canonical JSON to agent-bom for findings, graph, policy, and exports. - **MCP registry freshness gate** — `agent-bom registry status` now reports stale/never-synced registry state with `needs_refresh` and `recommended_action`, and `--fail-on-stale` gives release, demo, and CI pipelines a hard gate for bundled MCP intelligence freshness. ### Changed - **Pre-pilot proxy/gateway hardening** — SSE proxy policy checks now match stdio/gateway policy scope, gateway upstream handling has bounded resilience, and remote runtime HTTP mode requires explicit auth unless an operator opts into insecure local behavior. - **Self-hosted deployment contract** — Helm and deployment docs now state the BYO Postgres contract clearly, including the expected `AGENT_BOM_POSTGRES_URL` secret shape for production profiles. - **Fleet and scanner state isolation** — fleet graph nodes preserve endpoint identity for same-named agents across devices, and local database scan preference is threaded through `ScanOptions` instead of shared module state. ### Fixed - **Discovery provenance in exports and UI** — SARIF, OCSF, CycloneDX, and dashboard trust surfaces now retain sanitized discovery provenance, permissions-used, and scan-mode context so auditor-facing outputs match JSON/API evidence. - **Release/readiness alignment** — README, site docs, OpenClaw skills, Glama/MCP registry manifests, Docker/Helm references, and package metadata are aligned for the v0.83.4 release surface. --- ## [0.83.3] – 2026-04-30 ### Fixed - **Wheel inventory schema packaging** — `inventory.schema.json` now ships inside the installed `agent_bom` package, so PyPI users can run `agent-bom agents --inventory ...`, operator-pull adapters, and skill-mediated inventory flows without a source checkout. - **Inventory error exits** — missing inventory schema errors are now surfaced as explicit `--inventory` parameter failures with exit code 2 instead of falling through generic CLI handling. - **Interactive GHSA checks** — unauthenticated single-package GHSA rate-limit responses now fail fast instead of pausing for the fleet-scan backoff window, while multi-package scans preserve the bounded retry behavior. ### CI - **Wheel content guard** — PR and release package builds now fail if required JSON schema package data is missing from the wheel. --- ## [0.83.2] – 2026-04-30 ### Fixed - **Release gate determinism** — the tag publish workflow now uses `pip-audit` as the hard Python dependency release gate and keeps `agent-bom` self-scan SARIF as bounded evidence without opportunistic DB refresh, preventing third-party enrichment drift from cancelling a release after the build and container gates have already passed. --- ## [0.83.1] – 2026-04-29 ### Fixed - **Release workflow stability** — reusable docs deployment now honors `deploy: false` when invoked by the release workflow, preventing a tag release from trying to deploy GitHub Pages as part of package publishing. - **Post-merge SAST time budget** — post-merge source analysis now uses the bounded `agent-bom code` analyzer and converts its JSON to SARIF, preserving Security tab upload coverage without running the broad scan pipeline. --- ## [0.83.0] – 2026-04-29 ### Added - **Scope-zero discovery and pushed inventory workflows** — operator-pull adapters now let teams collect AWS, Azure, and GCP inventory inside their own boundary, emit canonical inventory JSON, and choose whether to stop at the file boundary or explicitly hand the inventory to `agent-bom agents --inventory` for findings, graph, policy, and exports. - **Agentic skill surfaces** — bundled AWS discovery and vulnerability-intelligence skills define standalone, guardrailed workflows for AI-agent users. Skills default to explain/discover/check modes and make any scan, push, or export handoff explicit. - **Discovery provider contracts** — `/v1/discovery/providers` and the extension registry contract now describe provider scan modes, permissions used, network boundaries, redaction posture, and scope-zero extension modes without loading third-party provider code by default. - **End-to-end discovery provenance** — inventory, packages, findings, graph exports, SARIF, UI surfaces, and pushed results now preserve discovery provenance, mapping method, confidence, lifecycle fields, cloud origin, permissions used, and reachability context through the canonical model. - **Extension entry-point registries** — cloud providers, connectors, and inventory parsers now have opt-in entry-point registry foundations for plugins and SDK-built integrations while preserving built-in behavior when extension loading is disabled. ### Changed - **Cloud discovery normalization** — AWS, Azure, GCP, Databricks, Snowflake, CoreWeave, Nebius, Hugging Face, OpenAI, W&B, and MLflow assets now use service/resource-type-aware `cloud_origin` envelopes, lifecycle fields, status, canonical package PURLs, and sanitized warning boundaries. - **Scanner and ingestion robustness** — scanner options are isolated per scan, AWS provider discovery runs service collectors in parallel, external scanner ingestion preserves advisory metadata, and cross-environment correlation is bucketed by account/project context for fleet-scale scans. - **Agentic architecture documentation** — docs now explain the product/skill/MCP layering, secure handoff modes, subagent delegation boundaries, and how teams can use agent-bom locally, in CI, self-hosted, cloud-read-only, pushed inventory, or through AI-agent workflows. ### Security - **Launch metadata redaction** — MCP launch args, URLs, runtime errors, audit details, graph metadata, SARIF locations, CycloneDX properties, AI prompts, pushed results, and UI fallbacks are sanitized before storage, export, display, or prompt construction. - **MCP intelligence and gates** — MCP intelligence now carries confidence, source, recommendation, references, and remediation metadata; non-CVE findings are rendered in compact output, SARIF, graph/API surfaces, and `--fail-on-severity` gates. - **Proxy and scanner hardening** — proxy audit hash chains use a stable path-derived lock, server-to-client JSON-RPC reads are bounded, Docker/Podman MCP image commands scan through the image inventory path or fail closed, registry fallback matching is boundary-aware, and GHSA advisory lookups paginate with rate-limit handling. ### Fixed - **GitHub Pages deployment** — docs deploy on pushes by default again, preventing stale Pages output after successful docs builds. - **PR gate SARIF contract** — AppSec PR-gate SARIF output now uses real self-scan output and fails fast when focused modes cannot produce valid SARIF. - **Stranded PR handling** — retrigger automation and lockfile-normalization CI were hardened to reduce frozen PRs caused by GitHub's token anti-loop behavior. --- ## [0.82.3] – 2026-04-28 ### Added - **Reachability-aware blast radius** — the graph-walk dependency-reach engine that shipped in v0.82.0 is now wired into `BlastRadius` scoring and the dashboard. New `BlastRadius.graph_reachable` / `graph_min_hop_distance` / `graph_reachable_from_agents` fields are populated by `agent_bom.graph.blast_reach.apply_dependency_reachability_to_blast_radii` during the analysis phase of every scan; `calculate_risk_score()` applies a small contextual nudge (+0.5 reachable, −0.5 unreachable, env-overridable via `AGENT_BOM_RISK_REACHABLE_BOOST` / `AGENT_BOM_RISK_UNREACHABLE_PENALTY`) so reachable findings rise above otherwise-equivalent unreachable ones in triage. The vulns dashboard renders a "Reachable · N hops" / "Unreachable" badge next to KEV. Engine failures degrade to a no-op so a graph bug never breaks the scan path. Closes the v0.82.2 honest-gap on engine-vs-surfacing (#2040). - **KEDA-driven autoscaling on the control-plane API tier** — new `controlplane-api-keda-scaledobject.yaml` Helm template + `examples/eks-keda-values.yaml` production preset. Three default Prometheus triggers tuned to bursty scanner workloads: rate-limit pressure, p99 latency, and the new `agent_bom_scan_jobs_active` gauge. The static CPU/memory HPA is suppressed when KEDA is enabled so two HPAs never fight over the same Deployment. Closes the EKS scoring audit's "HPA custom metrics not wired" gap (#2035, #2037). - **`agent_bom_scan_jobs_active` Prometheus gauge** — first-class queue-depth gauge bumped at `enqueue_scan_job` and decremented in `_run_scan_sync`'s `finally` block. Floored at zero so an instrumentation gap absorbs gracefully rather than producing a negative scrape. Records `record_scan_completion(status)` at the same site, wiring up the previously-orphaned counter (#2037). - **Clustered Postgres scale evidence harness** — `scripts/run_postgres_scale_evidence.py` drives the real `agent_bom.api.postgres_*` modules at increasing scale (audit append, job put/get) with `--replicas N` for `ProcessPoolExecutor` fan-out so the run captures pool contention + advisory-lock cost, not just single-process throughput. New `.github/workflows/postgres-scale-evidence.yml` runs it manually + weekly against a `postgres:16-alpine` service container and uploads JSON evidence as a 90-day artifact. PRs do NOT run it — too slow and tuning-sensitive to gate on. Closes the v0.82.2 SLO doc's "no published clustered Postgres scale benchmark" gap (#2038). - **Auto-retrigger workflow for stranded PRs** — `.github/workflows/auto-retrigger-stranded.yml` runs `scripts/retrigger_stranded_pr.sh` on a `*/5 * * * *` cron against every open non-draft PR whose current head SHA has zero `Lint and Type Check` runs. Permanently neutralises the GITHUB_TOKEN-authored "Update branch" anti-loop suppression that intermittently stranded #1996, #2030, #2031, #2034, #2035 in this release cycle (#2036). - **Per-framework compliance coverage table** — `docs/ARCHITECTURE.md § Coverage per framework` publishes the bundled-control counts vs. source-standard size for all 14 frameworks. README + `SECURITY_ARCHITECTURE.md` + `MCP_SECURITY_MODEL.md` + `MCP_ERROR_CODES.md` link to it. Closes the v0.82.2 honest-gap on compliance breadth (#2032). - **Two-image deployment guidance** — new `docs/DEPLOY_PLATFORM.md § Container images — do I need both?` section with verifiable code refs (`server.py:685-708` mounts `ui_dist/`, `pyproject.toml:189` ships `ui_dist/**` as wheel package data). Single-host pilots only need `agentbom/agent-bom`; the second image is for Kubernetes deployments that scale / restrict / ingress the UI tier independently (#2039). - **Merge-queue runbook + helper script** — `docs/operations/CI_RUNBOOK.md § Permanent fix options` now documents the supported UI-only path for enabling merge queue, with `scripts/enable_merge_queue.sh --check` to inspect current ruleset state (#2034). ### Changed - **UI TypeScript is now strict on `noUncheckedIndexedAccess` + `exactOptionalPropertyTypes`** — closes the long-running tracking issue #1967. Every array/Record index access yields `T | undefined` and every `?:` field is treated as "absent OR T". 60 violations fixed across the UI tree, mostly via type widening at internal boundaries plus conditional-spread for 3rd-party React-Flow / Recharts integrations. ESLint already enforced `no-floating-promises` and `no-explicit-any` as `error`; `lightningcss` was already in `devDependencies`; UI version was already lockstep with the platform release process (#2030, #2033). - **Mypy strict phasing — four more API store modules** — `fleet_store`, `idempotency_store`, `schedule_store`, `scim_store` added to the per-module strict override list in `pyproject.toml`. Generic `dict` annotations widened to `dict[str, Any]`, `_local.conn` returns surfaced as concrete `sqlite3.Connection`, pydantic `model_validate_json` and platform-invariant helpers wrapped to satisfy `warn_return_any` under `--follow-imports=skip`. Refs #1969 (#2031). --- ## [0.82.2] – 2026-04-27 ### Fixed - **UI image multi-arch publish** — `ui/Dockerfile` hard-pinned `lightningcss-linux-x64-gnu@1.32.0`, which broke the arm64 leg of the v0.82.1 release pipeline's `Publish UI image` job (`docker buildx --platform linux/amd64,linux/arm64`) with `EBADPLATFORM`. The fix consumes the `TARGETARCH` build arg buildx already injects and installs the matching prebuilt only (`lightningcss-linux-arm64-gnu` for arm64, `lightningcss-linux-x64-gnu` for amd64). v0.82.1 published the Python package, main API/CLI image, Helm chart, Sigstore signature, SLSA provenance, and CycloneDX SBOM successfully; only the standalone dashboard UI image at `agentbom/agent-bom-ui:0.82.x` was missing. v0.82.2 republishes that image for both architectures (#2025). --- ## [0.82.1] – 2026-04-27 ### Fixed - **Dashboard build under `output: "export"`** — `ui/app/graph/page.tsx` was using `export const dynamic = "force-dynamic"`, which is incompatible with Next 16's static export and aborted the v0.82.0 release pipeline at the Build/dashboard step (PyPI + Docker Hub publish jobs were skipped). Replaced with `next/dynamic({ ssr: false })`, the standard pattern for client-only components (`@xyflow/react` needs DOM) inside a static export. Re-enables the release pipeline; v0.82.0 stayed a no-op tag with no published artifacts. --- ## [0.82.0] – 2026-04-27 ### Added - **Graph-walk dependency reachability engine** — new `agent_bom.graph.compute_dependency_reach` (in `src/agent_bom/graph/dependency_reach.py`) runs BFS from every agent node along `USES` / `DEPENDS_ON` / `CONTAINS` / `PROVIDES_TOOL` edges and reports per-package `min_hop_distance` + `reachable_from` plus per-vulnerability summaries. **Engine half only.** Surfacing reach in blast-radius scoring and the dashboard follows in a separate PR; this release does not change scoring behaviour. Closes the engine half of #1896 (#2009). - **JSON Schema (draft 2020-12) generated from API Pydantic models** — `scripts/generate_v1_schemas.py` walks every public model in `agent_bom.api.models`, emits `docs/schemas/v1/.json` per model plus an `index.json` manifest. CI gates the drift via `--check`. SDK consumers can codegen against the published surface. Closes #1963 (#2007). - **Row-virtualized agent list pages** — `ui/app/agents/page.tsx` configured + installed agent cards now render through `@tanstack/react-virtual`'s `useVirtualizer` with `measureElement` for variable-height rows. Enterprise estates with thousands of agents no longer render every card flat. Vitest covers the windowing math. Refs #1955 — agents half closed; vulns table flat path is already paginated, grouped path windowing tracked separately (#2006). - **Cross-environment correlation framework + AWS Bedrock matcher** — local agents and cloud-discovered Bedrock runtimes are now matched on the strict triplet of cloud account ID + region + model ID. Strong matches emit `CORRELATES_WITH` graph edges; partial matches stay visible as `POSSIBLY_CORRELATES_WITH` with a `matched_signals` evidence list so reviewers can see candidates without the platform conflating them. Phase 1 of #1892; Phase 2 (Azure OpenAI / Functions, #1992) and Phase 3 (GCP Vertex / Cloud Run, #1993) plug into the same dispatch. - **Azure OpenAI cross-environment matcher** — extends the cross-environment correlation framework to Azure OpenAI deployments. Strict triplet is subscription ID + Cognitive Services account name + deployment name; explicit `OPENAI_API_TYPE=open_ai` disqualifies the agent so an Azure-shaped match never fires for public-OpenAI clients. Cloud discovery for Azure OpenAI now emits a normalized `cloud_origin` envelope so the matcher has structured identity to compare against. Phase 2 of #1892 (#1992). - **GCP Vertex AI cross-environment matcher** — extends the cross-environment correlation framework to GCP Vertex endpoints. Strict triplet is project ID + location + endpoint ID; the project-ID format gate rejects arbitrary strings (e.g. "test", emails) from counting as a project match. The endpoint env value is also accepted as a full Vertex resource path so a single IaC-supplied identifier surfaces all three signals. Phase 3 of #1892 (#1993). - **Cloud origin lineage in the unified graph** — agents discovered with cloud metadata now promote `cloud_principal`, `cloud_resource`, and direct principal→agent edges so single-hop reachability queries no longer have to traverse the intermediate cloud_resource node. - **GPU and k8s GPU promotion** — GPU containers and Kubernetes GPU clusters now flow into the unified graph alongside the rest of the inventory. - **Static multi-agent topology edges** — framework-level agent topology is now materialized as graph edges so reviewers can see which agents delegate to which. - **System prompt and MCP prompt inventory** — system prompts and MCP server prompts are now captured as policy evidence and surfaced through the standard inventory paths. - **AI observability SDK inventory** — observability SDKs are detected and recorded as managed inventory. - **MCP stable error envelope** — MCP responses now carry stable `code` / `category` / `details` / `schema_version` fields and a published API parity matrix so SDK consumers can branch on machine-readable errors. - **Vanilla EKS production preset** — `deploy/helm/agent-bom/examples/eks-vanilla-values.yaml` ships a production-shaped preset for self-hosted EKS rollouts. - **Customer secret rotation adapter evidence** — secret rotation adapters now emit deterministic evidence so operators can prove a managed key was rotated by their KMS, not the platform. - **Native control-plane mTLS fallback** — the API can terminate mTLS itself when no mesh or front proxy is available, with a posture surface on `/v1/auth/policy`. - **Frontend API error taxonomy + GET caching/dedup** — the dashboard API client now exposes a typed error taxonomy and dedupes/caches GET requests with prefix-scoped invalidation. - **Columnar CIS benchmark trend aggregation** — CIS results persist into a fact table dimensioned by cloud × section × status × severity × time bucket, with a new `/v1/compliance/cis/trends` endpoint and AWS/Azure/GCP cross-cloud fixtures so operators can graph drift over time. Closes #1832 (#2013). ### Changed - **Tenant quota enforcement is now atomic per tenant** — new `tenant_quota_guard(tenant_id, *checks)` context manager in `agent_bom.api.tenant_quota` holds a per-tenant `threading.Lock` (single-process atomicity) **and**, when `AGENT_BOM_POSTGRES_URL` is set, a session-scoped `pg_advisory_lock` keyed on `sha256(tenant_id)` for cross-replica atomicity. Wraps the (check + insert) pair in `scan`, `schedules`, `observability/push`, `scheduler-trigger`, and `fleet-sync` route handlers so concurrent requests serialise per tenant and the second caller sees the first caller's row in its check (audit-4 #2008 + audit-5 PR-B #2011). - **Workflow timeout coverage** — every job in `.github/workflows/` now declares `timeout-minutes`, including reusable-workflow callers (`uses:`) which were silently inheriting the 360-minute GitHub default. New `scripts/check_workflow_timeouts.py` gates drift in CI (#2008, #2010). - **Dependabot UI lockfile workflow** — `npm run lock:normalize` was replaced with the inline `npm install --package-lock-only --ignore-scripts` so a Dependabot branch can't redefine the script under the privileged `pull_request_target` token. - **Centralised tenant resolution for CLI and MCP** — CLI and MCP entry points now resolve tenant id through one shared helper instead of per-surface ad-hoc logic. - **Backpressure posture surfaced on `/v1/auth/policy`** — the operator policy endpoint now reports adaptive backpressure state (paths, p99, retry-after) alongside the auth and rate-limit posture. - **CSP source-of-truth centralised** — `ui/next.config.ts` and `ui/vercel.json` now share one CSP definition; `script-src 'unsafe-inline'` is temporarily restored pending the hash-pinning collector. - **Docker compose deployment** — platform compose files now use Docker secrets for Postgres credentials and align healthchecks across services. - **Docker base alignment** — runtime images now use LTS base versions and the build pipeline gates on the Glama and image-policy checks. - **Floating reference policy** — references to mutable upstream tags are now disallowed in build inputs by automated policy. - **Postgres sizing guidance + weekly scale-evidence regen** — `docs/perf/` documents `pg_size_pretty` sizing for 1k/5k/10k estates and a scheduled CI run keeps `docs/perf/results/` fresh. - **Generated `AGENT_BOM_*` env reference** — the env-var reference is now generated from `config.py` and CI fails if the doc drifts from the source. ### Fixed - **Graph `add_edge` no longer drops second-add evidence on dedup** — when the builder adds the package-path edge first and the blast-radius edge second for the same `(source, target, relationship)`, the second edge's `evidence` dict (cvss, epss, kev, attack tags) is now merged into the kept edge instead of being silently discarded. Kept side wins on key conflicts so existing order-of-arrival semantics for shared keys are preserved (audit-5 PR-A #2010). - **`_resolve_affected_server_ids` intersection collapse is now logged** — the narrow-by-server / narrow-by-agent intersections silently emptied when the named filter and the package-path candidates were disjoint. A debug log now surfaces report inconsistency to operator logs without changing the production narrow-by-all-filters semantics (audit-5 PR-A #2010). - **SAML relay-state cleanup runs on issue too** — `_new_saml_relay_state()` previously inserted into `_SAML_RELAY_STATES` but never swept expired entries, letting an attacker who issued nonces but never completed the SAML round trip grow the in-memory map unbounded. Sweep on issue too (audit-5 PR-A #2010). - **`release.yml` docs-site reusable caller missed timeout** — the audit-4 sweep added `timeout-minutes` to 29 jobs but skipped `docs-site` because the gate's `_is_reusable_caller()` helper returned `True` for any job with `uses:`. Reusable callers actually need their own timeout (the called workflow's per-job timeouts don't bound the caller; GitHub's default is 360 minutes). Gate fixed + `docs-site` now declares `timeout-minutes: 20` (audit-5 PR-A #2010). - **Release and post-merge job timeouts** — every release-pipeline and post-merge-self-scan job now has an explicit `timeout-minutes`; runaway jobs no longer hold scarce runners. - **Container rescan checkout pinned to v6** — the daily image rescan now uses a v6-pinned `actions/checkout` SHA aligned with the rest of the pipeline. - **main-ui-smoke boot script** — the standalone container boot script now assembles the `.next/static` tree explicitly (`rm`/`mkdir`/`cp -a`) so a missing source dir no longer aborts the smoke under `set -e`. - **Frontend contract hygiene** — closed frontend contract gaps surfaced by the post-v0.81.3 audit. - **Audit contract runtime gaps** — closed runtime gaps in audit-log integrity, signing, and lifecycle posture surfaced by the post-v0.81.3 audit. - **Adaptive backpressure retry-after jitter** — retry-after now uses multiplicative jitter so colocated callers don't all retry on the same boundary at base ≈ 1s. - **`scripts/retrigger_stranded_pr.sh` race** — the close→reopen gap now polls the GitHub API until the PR's state is observably `closed` before issuing the reopen call (was a fixed `sleep 2`). Prevents the reopen from racing against propagation and silently no-opping. - **`release.yml` docs-site invalid `timeout-minutes` on reusable caller** — GitHub Actions rejects `timeout-minutes` on a job whose body is `uses: ./.github/workflows/...`; the field made `release.yml` fail validation on every push to main. Removed the field from the `docs-site` caller and reverted `_is_reusable_caller()` in `scripts/check_workflow_timeouts.py` so the gate skips reusable callers (with a `Why:` comment so the next contributor doesn't re-add the broken field) (#2016). - **`scripts/run_scale_evidence.py` ValueError on outside-ROOT `--output`** — `args.output.relative_to(ROOT)` raised when the operator passed an absolute path outside the repo. Wrapped in `try/except` with a fallback to the absolute path (#2016). - **Vulnerability table grouped-view windowing** — the grouped-by-package and grouped-by-source paths in `ui/app/vulns/page.tsx` now cap each group at `PAGE_SIZE` with an overflow notice, matching the flat-mode windowing already in place. Closes the vulns half of #1955 (#2015). ### Security - **Six missing UI relationship colors + Vitest invariant** — `RELATIONSHIP_COLOR_MAP` in `ui/lib/graph-schema.ts` was missing `REMEDIATES`, `TRIGGERS`, `MANAGES`, `OWNS`, `PART_OF`, `MEMBER_OF`. `MANAGES` was the freshest gap — the cloud_principal → agent edge added in #1996 was rendering without colour. New `ui/tests/graph-schema-color-invariant.test.ts` walks every `RelationshipType` value and fails when any is missing from the colour map (audit-4 #2008). - **`shutil.which()` → absolute path TOCTOU** — `proxy_sandbox.resolve_container_runtime` and `filesystem._scan_archive` now resolve the binary via `shutil.which` once and pass the absolute path through to `subprocess`, closing the small PATH-substitution window between resolve and exec (audit-4 #2008). - **`O_NOFOLLOW` on skill-bundle hash read** — `skill_bundles._sha256_file` now opens with `os.O_RDONLY | os.O_NOFOLLOW` so the kernel itself rejects a symlinked leaf, closing the gap between the prior symlink check and the read (audit-4 #2008). - **Auth attempt counter is clustered-mode visible** — `_check_auth_session_rate_limit` emits a one-shot WARNING log on first use whenever clustered control-plane mode is detected (`AGENT_BOM_POSTGRES_URL` or `AGENT_BOM_REQUIRE_SHARED_RATE_LIMIT`), so operators see the cross-replica multiplier on the in-process counter. PR-A introduced the warning (audit-5 PR-A #2010); the Postgres-backed counter that fully closes the gap landed in PR-C #2012 (see entry below). - **Cluster-safe shared auth state** — auth session attempt counters and revoked session nonces now persist through `agent_bom.api.shared_auth_state`, which auto-selects an `InMemoryAuthState` backend by default and a `PostgresAuthState` backend when `AGENT_BOM_POSTGRES_URL` is set. Closes the cross-replica visibility gap that PR-A only warned on; SQL is parameterised through module-level constants to keep the surface Bandit-clean (audit-5 PR-C #2012). - **Body-drain middleware slowloris floor** — `MaxBodySizeMiddleware` now enforces a configurable minimum throughput (`AGENT_BOM_BODY_MIN_BPS`, default 256 B/s) on request-body reads so a slow client can no longer hold a worker indefinitely while staying under the size cap (audit-5 PR-C #2012). - **Auth middleware hardening** — header normalisation, exempt-path startup assertions, and tightened trust-proxy posture across the auth middleware stack. - **Tenant RLS bypass guard now under test** — the `APIKeyMiddleware` defence-in-depth check that rejects any request still inside an active `bypass_tenant_rls()` context is now covered by two regression tests (`tests/test_api_hardening.py`). Locks the guard so a future refactor cannot quietly drop it. - **MCP sandbox `image_pin_policy` posture surfaced** — `/v1/auth/policy` now reports the deployment-wide default and recommends `enforce` for production. - **Cross-parser dedup proofs + Postgres RLS red-team test for `scan_jobs`** — added structural and runtime guards proving a session bound to tenant B cannot read tenant A `scan_jobs` rows under a non-superuser role. - **Dependabot UI lockfile workflow no longer trusts the PR `scripts.lock:normalize` entry** — replaces the `npm run lock:normalize` step with an inline `npm install --package-lock-only --ignore-scripts` so a Dependabot branch can't redefine the script under a privileged `pull_request_target` token. ### Internal - **Tracked Finder duplicate artifacts blocked** — CI now refuses to merge tracked macOS Finder duplicate files (e.g. `… 2.md`). - **Real Postgres integration contract** — `tests/test_postgres_integration.py` now exercises real Postgres for job, audit, and RLS contracts. - **Stricter mypy on four more API modules** — `agent_bom.api.scim`, `agent_bom.api.storage_schema`, `agent_bom.api.tenant_quota_store`, `agent_bom.api.tracing` now run under the per-module strict overrides (`disallow_untyped_defs`, `disallow_incomplete_defs`, `warn_return_any`, `warn_unused_ignores`). Phase 3 of #1969 (#2003). - **UI `lib/api.ts` presentation helpers extracted** — `severityColor`, `severityDot`, `formatDate`, `isConfigured` moved to `ui/lib/api-format.ts` and re-exported from `lib/api.ts` so 50+ caller imports keep working unchanged. First step toward the broader decomposition tracked in #1965 (#2004). - **Pending-digest CI gate now ages markers out at 24h** — `scripts/check_docker_base_policy.py` reads each `# pending-digest` marker's `git blame --porcelain` committer-time and fails when older than `PENDING_DIGEST_MAX_AGE_SECONDS` (default 86400). Stops the marker from quietly outstaying its purpose if dependabot's docker job misses a bump (audit-3 #2005). - **`/v1/posture/backpressure` explicit `_ROLE_RULES` entry** — narrower entries listed before broad `/v1/posture` for grep/audit clarity. Behaviour unchanged (audit-3 #2005). - **`_clean_graph_part` fallback chain for `service`** — provider's two-source fallback chain now also applies to service (recovers `-` segment from `agent_dict.source`); `resource_type` keeps the literal placeholder (audit-3 #2005). - **README cloud CSP inventory** — README header now enumerates AWS, Azure, GCP, Snowflake, Databricks, CoreWeave, Nebius next to "cloud" (audit-3 #2005). - **Tenant RLS bypass guard tests** — `APIKeyMiddleware`'s defence-in-depth check that rejects requests entering with `bypass_tenant_rls()` still active is now under regression coverage in `tests/test_api_hardening.py` so a future refactor can't quietly drop the guard (audit-2 #2002). - **`scripts/retrigger_stranded_pr.sh` close→reopen race** — now polls the GitHub API until the PR's state is observably `closed` before issuing the reopen call (was a fixed `sleep 2`). Prevents the reopen from racing against propagation and silently no-opping (audit-2 #2002). - **Hermetic Python scanner surfaced in docs** — README and `docs/ARCHITECTURE.md` now name the single-language stack (CLI / FastAPI / MCP / scanners / enrichment / blast / IaC / CIS in one Python interpreter, native dpkg/RPM disk-image parsers, `syft` opt-in tar-archive fallback only) along with the honest tradeoffs (slower at huge fanouts, higher per-package memory) (#2015). - **mypy strict overrides expanded to nine more modules** — `agent_bom.api.compliance_signing`, `dashboard_csp`, `metrics`, `scim`, `storage_schema`, `tenant_quota_store`, `tracing`, plus `agent_bom.backpressure` and `agent_bom.proxy_sandbox` now run under `disallow_untyped_defs` / `disallow_incomplete_defs` / `warn_return_any` / `warn_unused_ignores`. Phase 3 of #1969 (#2015). - **`docs.yml` Python pin aligned to 3.11** — the docs-build job now uses the same Python the rest of the workflows do, removing a 3.12 outlier from the matrix. --- ## [0.81.3] – 2026-04-23 ### Changed - **Deployment and runtime guidance** — the README, self-hosted EKS guide, endpoint fleet guide, and proxy-vs-gateway-vs-fleet guide now surface the current graph scale boundary, recommended self-hosted defaults, runtime deployment matrix, and discovery-confidence boundaries where operators actually make rollout decisions. ### Fixed - **Graph overview regression guardrail** — the graph API test suite now locks the default `/v1/graph` overview path to the store-backed `page_nodes` / `edges_for_node_ids` / `snapshot_stats` flow so filtered paging cannot silently fall back to full `load_graph()` materialization. - **Docker Hub release sync** — the release workflow now uses a Docker Hub short description that stays under the registry API byte limit, preventing the `Publish to Docker Hub` job from failing after image push. --- ## [0.81.2] – 2026-04-23 ### Added - **UI session and capability contract** — `/v1/auth/me` now exposes authenticated actor, tenant, backend role, UI-facing capability summaries, and explicit `can_see` / `can_do` guidance so the browser shell can reflect the real backend auth model instead of inferring permissions ad hoc. - **Endpoint enrollment identity contract** — managed endpoint onboarding bundles now emit stable `source_id`, `enrollment_name`, owner, environment, tag, and MDM metadata so fleet inventory can preserve one explicit endpoint identity model across Jamf, Intune, Kandji, and local rollout paths. ### Changed - **Release-managed version surfaces** — the bump/check scripts now manage compose and runtime version pins as first-class release surfaces so image/version drift fails fast in CI instead of leaking into post-tag cleanup. - **Snowflake schedule parity** — warehouse-native deployments now persist recurring scan schedules in Snowflake and wire `/v1/schedules*` through the same backend-selection path as jobs, fleet, and gateway policy stores. - **Snowflake exception parity** — exception workflows now persist through the Snowflake backend too, extending the warehouse-native control-plane boundary without overclaiming full Postgres parity. - **Snowflake tenant-scoped store lookups** — job, fleet, schedule, and exception lookups/deletes now carry tenant scope into the Snowflake store layer instead of relying only on post-hoc route checks, keeping the warehouse path aligned with the platform’s defense-in-depth tenant model. - **Graph search and slice filtering** — the control plane now uses indexed graph-node search paths with server-side entity, severity, compliance-prefix, and data-source filters so larger tenant snapshots do not fall back to broad client-side graph scans. - **Graph overview pagination** — the default `/v1/graph` overview path now pages nodes and page-local edges from the store instead of materializing whole snapshots in memory before pagination. - **Endpoint onboarding bundles** — managed endpoint rollout bundles now carry a machine-readable enrollment manifest plus optional stable fleet `source_id` wiring so Jamf, Intune, and Kandji pushes can keep one explicit endpoint identity contract instead of only raw install scripts. - **Deployment and product framing** — README, deployment docs, self-hosted diagrams, trust-boundary docs, and Snowflake-parity guidance now align around `AI supply chain and infrastructure`, one obvious pilot path, one obvious production path, and explicit self-hosted vs MSSP boundaries. - **MCP server modularization** — the monolith split continued with extracted shared scan pipeline, resource/prompt catalog, FastMCP bootstrap helpers, and runtime catalog tool registration while keeping `create_mcp_server()` behavior and public imports stable. ### Fixed - **Shield concurrency and API rate limiting** — shield now reuses a bounded async bridge instead of spinning up unbounded executor paths, and the in-memory API rate limiter is explicitly thread-safe. - **Platform record invariants** — persisted fleet and MCP observation records now normalize tenant identity and UTC ISO-8601 timestamps consistently on read/write so graph, fleet, runtime, and audit correlation work from the same canonical model. - **Audit and graph query hardening** — exception approval/revocation no longer allow actor spoofing, graph routes move sync store calls off the event loop, SQLite graph search falls back cleanly when FTS `MATCH` expressions error, and audit replay rejects malformed short HMAC values instead of truncating them into a false compare. ### Security - **Gateway hardening** — scoped API keys are now enforced on the routes that already advertise scoped auth behavior, and gateway 404 responses no longer leak tenant-specific upstream details. - **Runtime monitor defaults** — the optional monitor DaemonSet now uses a dedicated service-account path, disables automounted service-account tokens, and is documented as an explicit zero-trust, off-by-default runtime surface rather than an assumed deployment requirement. --- ## [0.81.1] – 2026-04-22 ### Added - **Inventory-first MCP visibility** — the control plane now surfaces MCP command/URL, auth mode, credential-backed configuration, fleet timing, and provenance across scans, fleet sync, gateway discovery, and persisted observations instead of forcing operators to infer source context from summary badges. - **Operator feedback surface** — the shipped UI now includes in-product `Share feedback` and `Report bug` entry points with a copyable support bundle instead of relying on out-of-band issue filing alone. - **Runtime rollout packaging** — endpoint proxy bundles can now be rendered as `.pkg`, `.msi`, Homebrew, and MDM-oriented rollout assets, and Kubernetes deployments can opt into proxy sidecar auto-injection through the packaged mutating webhook path. ### Changed - **Self-hosted runtime model clarity** — the product now documents `fleet`, `proxy`, and `gateway` as peer surfaces with explicit deployment/use guidance, tighter EKS rollout docs, clearer entrypoints, and an honest retention/security-lake model that matches the current code and storage backends. - **Security graph semantics** — the UI and docs now make snapshot identity, scope, timestamps, pagination, node identifiers, and blast-radius semantics explicit so graph investigation scales without inventing a second graph model in the operator workflow. - **Release-caveat guidance** — graph/load boundaries, screenshot-redaction scope, centralized managed-connection limits, and the contributor workflow around GitHub’s `Update branch` synthetic-head problem are now explicit in the shipped docs instead of living as tribal knowledge. ### Fixed - **AWS/EKS operator path** — the reference installer now includes preflight checks and post-deploy verification so self-hosted rollout is not "install and guess" anymore. - **Skill-audit correlation gap** — skill-audit findings now feed the graph instead of landing as an orphan analysis surface outside the main inventory and blast-radius model. - **Runtime contract coverage** — gateway rate-limit behavior and inbound OCSF normalization now have explicit contract tests instead of relying on indirect coverage only. ### Security - **Runtime hardening sweep** — middleware RBAC write-route coverage is closed, cached proxy policy bundles are Ed25519-signed and fail closed on mismatch, gateway policies can hot-reload without redeploy, and replay detection now uses a bounded long-window design instead of a short-lived exact-only cache. - **Deploy-time hardening** — the AWS/EKS rollout path now validates control-plane inputs before install, and packaged runtime operations document policy-signing rotation and cert-manager-backed webhook certificate renewal instead of leaving those as tribal knowledge. --- ## [0.81.0] – 2026-04-21 ### Added - **Hosted control-plane source workflows** — first-class source records and source-linked jobs are now joined by persisted schedule controls on `/sources`, so operators can create recurring runs against real `source_id` records instead of reading static guidance (#1602, #1606). ### Changed - **Blast-radius scoring semantics** — EPSS percentile tiers now influence blast-radius scoring directly, and the previous 35-point deduction ceiling has been removed so high-reach critical exposure does not flatten into the same score band (#1605). - **Package lookup hot path** — version parsing is cached and package presence checks are batched, cutting repeated database round-trips on larger scan inventories (#1605). - **Traceability on hot paths** — the API, graph builder, DB lookup path, and runtime proxy now emit OTEL spans with W3C trace propagation so control-plane and proxy activity share one trace context (#1605). ### Fixed - **Release-managed surface alignment** — package metadata, Dockerfiles, Helm values, runtime examples, registry manifests, and marketplace-facing version pins now align on `0.81.0` instead of leaving post-release drift for operators to discover manually. ### Security - **Tenant-scoped control-plane reads** — asset routes now enforce tenant scope directly instead of trusting caller-provided tenant context, closing the highest-risk cross-tenant read gap from the post-release audit (#1603). - **Fail-closed OIDC and audit integrity** — OIDC discovery now refuses unsafe tenant/JWKS combinations, audit records are chained instead of independently HMACed, and gateway requests validate API keys against control-plane state before relay (#1603). - **Per-tenant runtime fairness** — scan concurrency and operator policy surfaces now expose tenant-specific quota enforcement instead of relying on one global in-process ceiling (#1605). --- ## [0.80.1] – 2026-04-21 ### Fixed - **Standalone UI image release path** — the Next.js container build now emits the `.next/standalone` output expected by the published `agent-bom-ui` image, and CI smoke-tests that path before release. - **Version-surface coherence** — Helm examples, runtime sidecar manifests, release verification docs, and product metrics now align on `0.80.1` so the public release surfaces match the shipped tag. ### Security - **Tenant and gateway auth hardening** — Postgres-backed API key verification can now resolve non-default tenant keys during auth and gateway relay paths, instead of silently falling back to default-tenant visibility under RLS. --- ## [0.80.0] – 2026-04-21 ### Added - **Control-plane auth for the shipped UI** — OIDC, trusted-proxy browser auth, session API-key fallback, and runtime auth introspection now let the dashboard operate as a real operator surface instead of a same-origin-only shell. - **Hosted-product source registry baseline** — the API and UI now expose first-class source records, source-linked jobs, and persisted schedule state as the first slice of the hosted control-plane model. - **Signed release surfaces** — Helm OCI publish, UI image release wiring, and stronger release verification/docs were added to the productized deployment path. ### Changed - **P0/P1 audit closure** — visual leak detector races, timeout audit gaps, resolver/VEX strictness, ServiceMonitor/operator defaults, CSP documentation, and UI dependency/release guardrails were tightened across the release lane. - **Deployment docs and diagrams** — self-hosted operator guidance, EKS rollout docs, and enterprise topology explanations were rewritten to match the actual control-plane/runtime split in code. ### Fixed - **Gateway and runtime audit integrity** — timeout paths now audit correctly, OCR runs once per response instead of once per image block, and the control plane/runtime surfaces agree on the operator deployment contract. - **UI packaging accuracy** — README and deployment copy now describe the Python image and standalone UI image honestly instead of implying a single bundled live dashboard path. --- ## [0.79.0] – 2026-04-20 ### Added - **Multi-MCP gateway and rollout path** — central `agent-bom gateway serve`, fleet-driven upstream discovery, focused EKS pilot guidance, and deployment-first docs for self-hosted operator environments (#1551, #1552, #1554, #1555, #1560). - **Visual leak runtime enforcement** — `VisualLeakDetector` is now wired into gateway and proxy protection paths so screenshot and image tool responses can be redacted or blocked as part of the runtime policy surface (#1572, #1575). - **Bidirectional OTEL product surface** — OTLP export, W3C trace context, `/v1/traces` ingest, and runtime OTEL evidence are now called out as first-class operator capabilities in the shipped product surfaces (#1583). ### Changed - **Tenant-native persistence and parity** — fleet, policy, audit, baseline, trends, analytics, and Snowflake/Postgres-backed stores now query natively by tenant rather than relying on broad reads plus in-memory filtering (#1558, #1559, #1561, #1562, #1567, #1569). - **RBAC and control-plane hardening** — enterprise/compliance/auth-policy surfaces align on the current `admin` / `analyst` / `viewer` model with route-level and middleware-level enforcement kept in sync (#1576). - **Monolith reduction in core surfaces** — `mcp_server`, `ast_analyzer`, Postgres stores, and console output were split into focused modules while preserving CLI/API behavior and published contracts (#1561, #1564, #1565, #1566). ### Fixed - **Graph blast-radius hot path** — vuln-to-server edge resolution now uses indexed lookups instead of the prior nested agent×server cross-product in the graph builder (#1581). - **HTTP retry behavior under load** — outbound retry backoff now adds positive jitter so concurrent OSV and HTTP clients do not back off in lockstep (#1582). - **Tenant-blind enterprise reads** — baseline compare, trends, audit export, and related enterprise/operator surfaces now honor tenant scope consistently across backends (#1559, #1569). - **Write-route audit coverage** — exception deletion, SIEM test, schedule mutation, fleet sync/state updates, and related operator write paths now emit audit entries with actor and tenant context. - **Ignore-file error handling** — malformed YAML/JSON ignore files now fail through narrow parse errors instead of broad exception swallowing (#1582). ### Security - **Hardened audit evidence chain** — audit HMAC coverage now includes payload `details`, routes fetch tenant-scoped audit entries at the store layer, and exported evidence stays tamper-evident across backends (#1559). - **Transport and operator posture clarified** — HTTPS-external / trusted-boundary-internal deployment guidance, OTEL/OPA positioning, and current auth/RBAC behavior now match the live product and deployment docs (#1583). ### Docs - **Release and deployment alignment** — README, Docker Hub README, product brief, EKS guidance, backend matrix, and release-managed version surfaces are aligned on `0.79.0`. --- ## [0.77.1] – 2026-04-18 ### Fixed - **Release metadata alignment** (#1498) — corrected 0.77.0 follow-up: brought `pyproject.toml`, `uv.lock`, and integration listings to a consistent 0.77.1 after an intermediate packaging drift --- ## [0.77.0] – 2026-04-18 ### Added - **Live Kubernetes posture scanning** (#1489) — cluster-scoped scan path walks live API-server objects, correlates pod specs with image/CVE inventory, and emits findings through the unified pipeline - **Control-plane enterprise auth** — SAML SSO assertion exchange (#1487), API key rotation policy with audit trail (#1492), tenant quotas (#1486), and tenant-scoped rate limiting with Postgres tuning (#1493) - **Proxy & fleet durability** — idempotent fleet/proxy ingest (#1473), circuit breaker + DLQ for proxy audit delivery (#1494), service-mesh + policy-controller templates for EKS (#1495) - **Helm packaging for the control plane** (#1453) — end-to-end Helm chart with production operator defaults (#1458), operator observability + backups (#1472), encrypted backup restore path (#1485) - **MCP agent mesh surface** — agent context graph with lateral movement analysis, IaC findings stitched into the unified graph (#1426), programmable graph query traversal (#1427), mesh cleanup polish (#1470) - **Findings as first-class UI surface** (#1423) — unified, deep-linkable findings view across vulnerability, policy, and compliance sources with one-click drill into the security graph (#1395, #1397, #1399, #1400, #1401) - **Snowflake CIS password policy coverage** (#1429) and Snowflake storage backend parity (#1408) - **Live UI configurability** — runtime-configurable API endpoint (#1452), dashboard posture card unification (#1447), theme support across dashboard and graph surfaces (#1404, #1407, #1411, #1413) - **Data-sources product surface** (#1421), how-agent-bom-works explainer (#1440), and deployment/hosting guidance (#1444) ### Changed - **AST analyzer modularization** — JS/TS (#1424), Go (#1425), and shared models (#1420) extracted into focused helpers; SAST helper-chain findings reframed for clearer attribution (#1488) - **MCP server modularization** — specialized tool registrations (#1439) and runtime helpers (#1438) split out of the main server module - **Scanner modularization** — OSV helpers (#1418), runtime state helpers (#1417), risk/blast-radius helpers (#1416) split into dedicated modules - **CLI modularization** — option groups split into helper modules (#1434); wayfinding and doctor output polished (#1394) - **Proxy policy & audit split** (#1436) for cleaner policy boundaries - **Remediation scoring anchored to blast-radius risk** (#1443), not CVSS alone - **Prompt-injection analyzer signals tightened** (#1490) - **Analytics ingest batched** for flagged trace events (#1428) ### Fixed - **Operator drilldown UX** (#1496), pilot UI reliability (#1471), mesh UI cleanup + README visuals (#1470) - **Pilot rate limiting + control-plane HA hardening** (#1460), pilot hardening follow-ups (#1457), pilot auth + endpoint fleet path (#1456) ### Security - **Gateway policy RBAC hardened** (#1451) - **Marketplace publishing surfaces hardened** (#1442) - **Supply-chain trust + extras audit made explicit** (#1441) - **UI dependency + validation contract hardened** (#1446) ### Docs - **Enterprise scale guidance + benchmark harness published** (#1459) - **Data ingestion + security model documented** (#1437) - **Docs rebuilt on release tags** (#1419) - **Sidebar IA clarified** (#1412), scan page product surfaces clarified (#1415) ### Infra - **mypy phase 2 body checking enabled** (#1433) - **Cloud normalization coverage with fixtures** (#1410) - **Storage backend contract exposed on health** (#1409) - **Backend parity + Snowflake modes documented** (#1408) --- ## [0.76.4] – 2026-04-13 ### Added - **Release-surface refresh** — README, PyPI, and Docker Hub now show the current product path with real screenshots, tightened copy, clearer architecture/graph visuals, and a shorter demo flow - **CVE and graph drilldowns** — vulnerability rows and graph detail panels now provide richer fix, impact, compliance, and evidence context instead of acting like dead text ### Changed - **Summary-first loading** — dashboard, jobs, activity, vulnerabilities, mesh, context, and insights now unlock from lightweight job summaries first and only hydrate deeper scan data when the active panel needs it - **Graph defaults and fallbacks** — focused graph views, empty states, findings fallbacks, and posture labels now favor scoped, readable investigation paths over dumping full topology state at once - **Docker freshness operations** — release automation now includes an explicit Docker `latest` refresh path so base-image fixes can be rebuilt and republished without waiting for a feature release ### Fixed - **Snowflake SQL hardening** — notebook identifier quoting and `days` coercion now validate and escape values before SQL interpolation - **Jobs summary contract** — pushed and completed scan rows now keep `completed_at`, `error`, and summary metadata aligned across API, dashboard, and jobs surfaces - **App-router release build stability** — release pages that rely on search params now render safely under `Suspense`, fixing the current Next.js app-router build path - **AST/SAST depth wave** — validator-aware guards, transformed-return sanitizers, JS/TS early exits, and cross-file helper modeling reduce false positives while improving Python, JS/TS, and Go parity ### Security - **Container rebuild response** — Docker refresh and rescan wiring now close the loop for newly published Alpine fixes instead of relying on manual Docker Hub inspection - **Snowflake query validation** — user-controlled notebook and date inputs are now coerced or quoted before execution, removing the identified injection and query-shape risks --- ## [0.76.2] – 2026-04-09 ### Changed - **Patch release alignment** — managed release/version surfaces are now aligned on `0.76.2` for the next patch cut ### Fixed - **Alpine package visibility** — local vulnerability DB sync now ingests Alpine secdb in addition to OSV, so Alpine package advisories like the recent `openssl` and `util-linux` fixes are detected without waiting on OSV lag - **Alpine scanner coverage** — Alpine OS-package fallback queries now include `v3.23`, matching the current container base branch - **Container hardening** — the Docker build now upgrades installed Alpine packages during both builder and runtime stages instead of only bumping `zlib` - **Release image gating** — CI and release image scans now fail on fixable `MEDIUM+` and `UNKNOWN` image vulnerabilities while ignoring upstream-unfixed image findings ### Security - **Container CVE response** — the patch release closes the fixable Alpine `openssl` and `util-linux` image findings and adds stronger pre-release guardrails to stop similar Docker regressions from shipping unnoticed --- ## [0.76.1] – 2026-04-09 ### Added - **CLI output parity for reporting commands** — `check`, `report diff`, and `report history` now have clearer machine-readable behavior, and reporting surfaces that were still missing `--quiet` now support quiet scripting flows - **CLI troubleshooting coverage** — the shipped docs now include a dedicated debug guide for quiet mode, stdout vs file output, discovery triage, and verification workflows ### Changed - **Patch release alignment** — release-managed files, Docker/Helm metadata, OpenClaw skills metadata, docs, registry surfaces, and action examples are now aligned on `0.76.1` - **Verification status wording** — package provenance verification now distinguishes missing attestations from service unavailability instead of collapsing both into a generic unknown state ### Fixed - **Quiet mode consistency** — reporting and analysis commands now suppress headings/export chatter when `--quiet` is requested - **Verify JSON output** — `agent-bom verify --json` no longer prepends human console banners before the JSON payload - **Graph contributor install contract** — graph centrality dependencies and contributor install paths were aligned so graph analysis works in a clean optional-extra install - **Live MITRE/STIX parsing** — ATT&CK/CAPEC runtime parsing now handles the current upstream payload shape and restores live CWE→ATT&CK mapping - **Docker Hub release hardening** — release sync, cleanup retention, and version-alignment checks now match the real Docker tag contract and fail loudly on drift - **Release bump automation** — stale version-bump patterns were removed so dry-run and check mode only flag real managed release surfaces ### Security - **Supply-chain verification clarity** — provenance verification now reports whether attestations are absent or temporarily unavailable, reducing ambiguous release-audit results for package verification --- ## [0.76.0] – 2026-04-09 ### Added - **Unified graph product path** — persisted snapshots, current-state and diff views, attack-path drilldown, search, impact, delta alert delivery, and Postgres-backed graph persistence are now part of the shipped CLI/API/dashboard flow - **Multi-language AST/SAST depth** — Python, JS/TS, and Go analysis now include stronger cross-file and taint-aware coverage, plus SARIF import and cleaner custom-rule handling - **Container layer attribution** — image findings now retain per-layer package provenance so output can show which layer introduced a vulnerable package - **PDF report export** — `agent-bom scan -f pdf -o report.pdf` now renders the existing HTML report through an optional WeasyPrint-backed export path ### Changed - **README and architecture visuals** — product positioning, hero commands, and architecture diagrams were shortened and tightened to match the current shipped path without overflowing cards or stale counts - **Demo CLI polish** — demo and offline copy are shorter, and the scan path no longer prints redundant inner vulnerability banners when the outer progress bar is already rendering the step - **Release-managed versioning** — docs, deployment files, Helm, OpenClaw, registry metadata, and action examples now align on `0.76.0` ### Fixed - **Graph correctness and scale** — snapshot isolation, tenant propagation, search escaping, delta dispatch semantics, and direction-aware traversal/reporting were hardened across the recent graph lane - **Scanner concurrency** — shared cache and scanner-global thread-safety issues were fixed and regression-tested - **Container evidence depth** — package metadata now tracks layer/package occurrences instead of flattening away provenance - **Release automation drift** — CodeQL SARIF upload is on v4 and no longer fails when a SARIF file was not actually produced ### Security - **Release dependency refresh** — cryptography was bumped to `46.0.7`, clearing the active moderate buffer-overflow advisory on the locked release path - **Graph delta delivery** — delta alerts now flow through the existing dispatcher/webhook surfaces instead of only being computed/export-ready --- ## [0.75.15] – 2026-04-04 ### Added - **API distributed tracing** — request-level `traceparent` propagation, `X-Trace-ID` headers, OTLP/HTTP export, and collector/reverse-proxy contract docs - **Postgres-backed API rate limiting** — shared throttle state across replicas via `api_rate_limits`, keeping `429` and `Retry-After` semantics consistent - **Skills AST-aware analysis** — fenced Python and JS/TS code blocks in skill/instruction files now get semantic risk detection for dynamic execution, shell/process execution, and file mutation - **Skills output schemas** — `skills scan` and `skills rescan` now ship explicit versioned JSON schemas for stable downstream consumption - **Helm monitoring surfaces** — readiness/startup probes, optional metrics service, optional `ServiceMonitor`, and runtime `/metrics` wiring for Prometheus-friendly deployments - **Postgres enterprise persistence** — audit log and trend history now have Postgres backends with tenant-aware persistence ### Changed - **Demo wording** — the built-in `--demo` path is now presented as a curated sample agent + MCP environment, while real local/project scans remain the primary product story - **Tenant isolation posture** — enterprise stores, gateway policy surfaces, audit/trend history, and shared rate-limit state now align under the same tenant-boundary model - **Security automation** — daily preventive workflows, deployment freshness checks, and authenticated Railway verification now better reflect real release state ### Fixed - **GitHub Action enterprise networking** — proxy and custom-CA environment variables now pass through consistently during install and scan steps - **OpenClaw packaging metadata** — stale skills test-count references were updated to current repo reality - **Postgres schema drift** — schema summaries, RLS coverage assertions, and table counts now match the current tenant-bearing model ### Security - **Postgres RLS completion** — all tenant-bearing Postgres tables now enforce row-level security, with shared caches and infra-only tables explicitly excluded from that boundary - **Enterprise auth maturity** — RBAC route enforcement, OIDC tenant-claim scoping, authenticated request tracing, and shared rate-limiting now operate together as the production API contract --- ## [0.75.14] – 2026-04-03 ### Added - **Next.js Insights page** (`/insights`) — SupplyChainTreemap, BlastRadiusRadial, PipelineFlow, EpssVsCvssChart, VulnTrendChart wired to real scan data; treemap cells are clickable and drill down to `/vulns` - **Gateway enforcement chart** — audit tab shows stacked bar of blocked/alerted/allowed actions per tool - **Governance findings chart** — stacked bar of finding severity by governance category - **Activity query chart** — bar chart of agent query pattern frequency - **Fleet lifecycle chart** — bar chart of agents by lifecycle state - **Jobs status donut** — pie chart summarising job queue by status - **`ui/components/empty-state.tsx`** — reusable `EmptyState` + `ErrorBanner` components used across pages - **Retry buttons** — Activity and Governance error states now include a Retry button - **SECURITY.md** expanded — response SLA, known limitations, API security model, disclosure timeline - **PR template** — added Related Issues, TypeScript check, breaking changes, checklist sections - **pre-commit hooks** — added `check-yaml`, `check-json`, `check-toml`, `end-of-file-fixer`, `trailing-whitespace`, `detect-private-key`, `check-merge-conflict`, `mixed-line-ending` - **`agent-bom mcp scan`** — focused MCP server package audit path for pre-install checks - **Compliance narrative CLI** — auditor-facing narrative export from saved scan reports via `agent-bom report compliance-narrative` - **MCP caller governance** — per-caller rate limiting, request tracing, and richer tool metrics now flow through the MCP server metrics surface - **Remote MCP startup contract** — Railway/remote deployments now use an explicit bearer-token contract instead of accidental anonymous exposure ### Fixed - **JSON report import** — file upload now validates size (10 MB), schema, prototype-pollution keys, and finite numeric values before use (`ui/lib/validators.ts`) - **`generated_at` TypeScript error** — `ScanResult` does not have `generated_at`; use `scan_timestamp` instead - **JetBrains claim** — removed from active integrations; filed as issue #412 for proper implementation - **`skills scan` path handling** — bundle identity now supports referenced files outside the primary file directory, fixing repo-local scans against shared security assets - **`check` ecosystem ambiguity** — pre-install checks now fail closed on genuinely ambiguous package names and use version-aware registry detection to avoid cross-registry false positives - **`skills scan --verbose`** — added parity with other CLI surfaces for easier debugging - **Runtime CLI warning noise** — async proxy tests now use async-aware mocks, removing unawaited coroutine warnings from that path - **Frontend/backend scan contracts** — UI API types now model `scan_performance`, richer `scorecard_summary`, `posture_scorecard`, and remediation metadata consistently with backend JSON output - **GitHub Action execution contract** — hardened argv handling, severity validation, pip caching, step summaries, and sanitized PR comment/report generation now match the documented Action behavior - **Runtime image provenance** — runtime Docker image now builds from repo source instead of reinstalling from PyPI, aligning image behavior with source and release verification - **MCP execution envelope** — sync and async tools now share bounded concurrency, timeout, metrics, path safety, and sanitized error handling - **Snowpark enterprise networking** — Snowpark image now supports enterprise proxy and custom-CA configuration like the other maintained image families ### Security - **JSON file upload** — `ui/lib/validators.ts` guards against DoS via oversized files, prototype pollution, and schema-invalid payloads (no new npm dependencies) - **API and remote MCP fail closed** — non-loopback API and remote MCP transports now refuse to start without explicit auth unless an insecure override is deliberately supplied - **Dependency security refresh** — LiteLLM was bumped to `1.83.0`, clearing the active 2026 GitHub security advisories on `main` --- ## [0.75.13] – 2026-04-01 ### Added - **Focused MCP server review** — `agent-bom mcp scan ` adds a narrower audit path for a single MCP server or command before adoption - **Compliance narrative CLI** — compliance narrative export is now reachable from the CLI for release and audit workflows ### Changed - **Release surfaces aligned** — README, PyPI, Docker Hub, site docs, Helm, OCI metadata, and publishing surfaces now share the same product description and release references - **Canonical product story** — product positioning, Claude/Cortex integration references, and repo-derived metrics now point back to the canonical brief and generated metrics appendix - **First-run guidance** — empty-state discovery help now shows concrete Claude, Cursor, Codex CLI, and Cortex CoCo config paths instead of circular retry suggestions - **SARIF defaults** — SARIF export now auto-enables enrichment when online so severity context lands in GitHub and downstream scanners by default ### Fixed - **Offline safety boundary** — offline scans now fail closed when the local vulnerability database is missing or incomplete instead of producing a false clean result - **Incomplete result visibility** — critical scanner and enrichment failures now surface warning summaries instead of silently degrading to partial output - **Skills scanning** — `agent-bom skills scan .` no longer crashes on repo-local path validation, and the command now supports `-v` / `--verbose` - **Package checks** — `agent-bom check` now resolves ambiguous package names more safely and avoids cross-ecosystem false positives - **Output format handling** — unknown output extensions now fail loudly instead of silently falling back to JSON - **ClickHouse query hardening** — analytics escaping was tightened and the associated tests expanded - **Release quality gates** — follow-up CodeQL, lint, mypy, FastAPI response-model, and regression issues from the stabilization lane were fixed before release ### Security - The `0.75.13` release closes the remaining pre-release P0/P1 safety issues from the final audit lane, including offline false-clean behavior, incomplete scan signaling, and ClickHouse query hardening --- ## [0.75.12] – 2026-03-29 ### Added - **First-class skills scanning** — `agent-bom skills scan` and `agent-bom skills verify` are now top-level CLI surfaces for instruction-file trust, provenance, and findings - **Live MCP tool capability scoring** — added capability-based tool/server risk assessment from `tools/list` introspection, surfaced through MCP and scan outputs - **Release demo refresh** — updated hero demo and release surfaces for `v0.75.12` ### Changed - **MCP tool surface** — docs and public surfaces now reflect the current 36-tool MCP server accurately - **Quickstart alignment** — CLI/docs/demo flows now point to the grouped first-class commands (`agents`, `skills`, `image`, `iac`) - **Advisory labeling** — unscored vulnerabilities are presented as advisories/pending severity instead of ambiguous unknowns - **Resolver continuity** — npm version resolution now prefers cached/bundled continuity under rate limiting instead of repeated blocking retries - **Supply-chain enrichment** — `--enrich` resolves package source metadata before OpenSSF Scorecard lookup and reports explicit enrichment coverage state ### Fixed - **Blast radius serialization** — package name/version/stable ID now propagate correctly in filesystem and JSON outputs - **Filesystem posture credibility** — fs/project scans no longer get penalized for missing MCP-only config context; posture and framework mapping now reflect the actual scan mode - **Framework tagging** — intrinsic vulnerability findings now carry framework tags in both agents and fs modes - **Remediation output** — remediation JSON now includes populated priority and action fields - **UI dependency hygiene** — aligned UI eslint peer range with Next.js-supported versions to remove install drift - **Scorecard source resolution** — npm/PyPI direct dependencies now fall back to source metadata resolution paths so repo URLs, homepages, and Scorecard repos populate end to end ### Security - No new release-blocking regressions introduced across the `0.75.12` stabilization lane; focused regression suites, UI tests, build checks, and release consistency checks remained green --- ## [0.75.0] – 2026-03-23 ### Added - **Dashboard UX** — posture grade (A-F) hero, top 5 attack path cards, security graph page with interactive React Flow, insight layer toggle (risk/credentials/default), 14-framework compliance heatmap - **Remediation page** — priority table sorted by blast radius impact, Jira ticket creation per finding, compliance impact summary, severity/framework filters, JSON export - **Compliance narratives** — `GET /v1/compliance/narrative` generates review-ready text per framework with control-level detail and remediation-compliance bridge - **`--posture` flag** — 5-line workstation posture summary for solo developers - **`--fixable-only` flag** — show only vulnerabilities with available fixes - **`agent-bom doctor`** — preflight diagnostic (Python, DB, network, Docker, MCP configs, API keys) - **Cross-agent behavioral detection** — `CrossAgentCorrelator` detects lateral movement (3+ agents same tool in 5min), anomaly baseline per agent - **SSE proxy transport** — `agent-bom proxy --url` for remote SSE/HTTP MCP servers - **SBOM multi-hop graph** — dependency depth tracking (A→B→C) + CycloneDX `vulnerabilities[]` ingest - **API rate-limit headers** — `X-RateLimit-Limit/Remaining/Reset` on all responses, `X-API-Version: v1` - **Jira API endpoint** — `POST /v1/findings/jira` with ephemeral credentials, SSRF-validated - **False positive feedback** — `POST/GET/DELETE /v1/findings/false-positive` with tenant-scoped persistence - **Break-glass endpoint** — `POST /v1/shield/break-glass` with admin RBAC + audit logging - **Prometheus `/metrics`** — fleet_total and fleet_quarantined gauges - **75 UI component tests** (Vitest + @testing-library/react) - **8 intent-based OpenClaw skills** — discover, scan, scan-infra, enforce, comply, monitor, analyze, troubleshoot - **CONTRIBUTING.md** — contributor onboarding guide - **Enterprise Deployment guide** — MDM push, fleet API, zero-credential architecture ### Changed - **Homepage reworked** — posture grade + blast radius chains at top, stats compressed to one row - **Compliance page** — now shows all 14 frameworks (was 6) - **Security graph** — uses pre-computed blast_radius scores (risk_score, is_kev, epss_score) - **All dashboard pages** — consistent Loader2 spinners, overflow-x-auto tables, confirmation dialogs on destructive actions, Snowflake-only banners in error state - **Vulns page** — pagination (50/page), search, FP feedback button, confidence scores - **Jobs page** — status filter tabs, search, pagination (25/page), JSON export - **Fleet page** — search, JSON export, confirmation on state transitions - **Agents page** — search by name - **CLI output** — severity text labels alongside colors (accessibility) - **CycloneDX** — `formulation` field identifies agent-bom as generator - **GitHub Action** — `exclude-unfixable` input for CI gating - **Architecture diagram** — compact horizontal layout (LR) - **Count alignment** — release surfaces were brought back to a single source of truth for that release's framework, rule, pattern, page, tool, and format totals ### Fixed - **Full-stack alignment** — `severity_source`, `confidence`, `nist_800_53_tags`, `fedramp_tags`, `automation_settings`, `vector_db_scan`, `gpu_infra` now serialized in JSON output (were silently dropped) - **Compliance router** — `/v1/compliance/narrative` no longer shadowed by `/{framework}` wildcard - **UI field names** — `risk_score ?? blast_score`, `summary ?? description`, `is_kev ?? cisa_kev` with backward compat - **Offline mode strict** — no silent network fallback when `--offline` set - **AST prompt detector** — `description`, `help`, `title` fields no longer misclassified as system prompts - **CodeQL SSRF** — defense-in-depth `validate_url()` at transport layer - **HSTS header** — `Strict-Transport-Security` added to all API responses - **OIDC SSRF** — `validate_url()` on discovery URL - **ECS/EKS test mocks** — updated to paginator pattern - **Protection engine** — `stop()` persists cleared kill-switch state, semaphore cache bounded to 8 entries - **Chain-hashed audit log** — each entry includes previous entry's HMAC for tamper-evidence - **Multi-tenancy isolation** — tenant_id enforced at middleware level - **Quarantine enforcement** — quarantined agents excluded from fleet list by default - **Log file permissions** — 0o600 on audit DB, fleet DB, log files - **Node.js 20 deprecation** — `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24` on dependency-review - **Local fonts** — Inter + JetBrains Mono bundled (no Google Fonts network dependency) ### Security - 10/10 OWASP web categories PROTECTED (verified by code audit) - SLSA L3 provenance on releases, Sigstore signing on PyPI - 91 SHA-pinned GitHub Actions, 0 npm/Python vulnerabilities - scrypt KDF for API keys, HMAC constant-time comparison, parameterized SQL everywhere ## [0.74.1] – 2026-03-22 ### Security - **Runtime**: Fix threat level comparison — `ThreatLevel` enum uses ordinal comparison; previously `CRITICAL > HIGH` was `False` (lexicographic), so escalations were never detected - **Runtime**: Per-session shield engine isolation — zero trust, no cross-session threat contamination - **Runtime**: Rate limiter now blocks (HIGH/CRITICAL severity) instead of alert-only (MEDIUM) - **Runtime**: HTTP protection server auth via `AGENT_BOM_PROTECTION_API_KEY` with constant-time comparison - **Runtime**: Single zero-width space now detected (was requiring 3+ consecutive chars, bypass fixed) - **Runtime**: Unicode path traversal (`\u002e\u002e`) detection added - **Runtime**: 3 new credential patterns (HashiCorp Vault, AWS session tokens, PagerDuty) — 112 total - **Runtime**: Drift baseline persisted to disk, survives engine restarts in shield mode - **Supply chain**: Go module provenance verification via sum.golang.org checksum database - **Supply chain**: Provenance results persisted in Package model (integrity_verified, provenance_attested) ### Fixed - **Compliance**: Wire NIST 800-53 Rev 5 tags in scanner pipeline (was defined but never called) - **Compliance**: Wire FedRAMP Moderate baseline tags in scanner pipeline - **Policy**: Add 9 missing framework tag fields to policy engine expressions (all 14 frameworks now accessible) - **Scanner**: Surface non-OSV ecosystem skips to users with per-ecosystem breakdown - **Scanner**: Track per-package CVE lookup errors and report at scan completion - **Scanner**: Add severity_source field for audit trail (cvss, osv_database, ghsa_heuristic) - **Scanner**: Bound semaphore cache to 8 entries (prevents memory leak in long-running API servers) - **Scanner**: Kill-switch state now persisted on stop() (was leaving stale blocked state on disk) - **Cloud**: ECS/EKS/SageMaker discovery uses boto3 paginators (was missing results beyond page 1) - **MITRE ATLAS**: Expanded from 8 to 30+ technique mappings across all tactic categories ### Added - `make dev` — starts API server + Next.js dashboard in parallel - `make install-all` — installs all development extras (dev + ui + mcp-server) - `dev-all` extra in pyproject.toml for one-command setup - `AGENT_BOM_CLOUD_DISCOVERY_TIMEOUT` config (default 45s) - Portable `.claude/launch.json` for dev server configs - Mermaid blast radius diagram in README - Mermaid architecture diagram in README - Compliance frameworks table in README ### Changed - README: ecosystem count 11 → 15, credential patterns 31 → 34, compliance frameworks 14 → 16 - MITRE ATLAS coverage documented accurately (30+ observable techniques) --- ## [0.74.0] – 2026-03-21 ### Dashboard & HTML Report - **Sidebar navigation** — collapsible left sidebar replaces top nav across Next.js dashboard (18 pages) and HTML report, with 5 grouped sections, command palette (Cmd+K), active link highlighting, mobile drawer (#993) - **React Flow edge fix** — topology graph nodes now connect properly with Handle components, eliminating all "null handle id" errors (#993) - **Topology enhancements** — nodes show server count, vuln count, credential indicators; animated edges for vulnerable connections; zoom controls; empty state (#993) - **HTML report sidebar** — fixed 220px sidebar with IntersectionObserver active section tracking, mobile responsive hamburger toggle, print-friendly layout (#993) ### Security - **Dependency CVE fixes** — pillow ≥12.1.1 (CVE-2026-25990 PSD OOB write), protobuf ≥6.33.5 (CVE-2026-0994 ParseDict DoS), pyjwt ≥2.12.0 (CVE-2026-32597 crit header bypass), tornado ≥6.5.5 (CVE-2026-31958 multipart DoS, GHSA-78cv-mqj4-43f7 cookie injection) - **CI/CD hardening** — all GitHub Actions pinned to SHA digests, no `@master` refs, scoped permissions ### Fixed - **Dashboard layout** — wider content area (1400px), CSS page transitions, thin scrollbar, card hover effects - **HTML report unused variables** — removed dead nav link variables (ruff F841) --- ## [0.73.0] – 2026-03-19 ### Architecture - **5-product CLI** — `agent-bom`, `agent-shield`, `agent-cloud`, `agent-iac`, `agent-claw` — one package, five entry points, zero duplication (#967) - `agent-bom` — BOM generation + vulnerability scanning - `agent-shield` — runtime protection (proxy, protect, guard, watch, audit) - `agent-cloud` — cloud infrastructure (aws, azure, gcp, snowflake, databricks, huggingface, ollama, posture) - `agent-iac` — IaC security (scan, policy, validate) - `agent-claw` — fleet governance (fleet, serve, api, schedule, report, connectors) - **Shared entry point factory** (`_entry.py`) — consistent error handling + update check across all 5 products - **Parameterized help categories** — each product shows relevant command groups in `--help` - **Full backward compat** — `agent-bom runtime proxy`, `agent-bom cloud aws`, etc. still work ### Added - **CycloneDX 1.6 ML BOM extensions** — native `modelCard`, `data` components, `machine-learning-model` type with `quantitativeAnalysis` for training metrics (#967) - **Agent-shield deep defense mode** (`--shield`) — correlated multi-detector threat scoring, `ThreatLevel` escalation (NORMAL→ELEVATED→HIGH→CRITICAL), automatic kill-switch on CRITICAL (#967) - **Graph-native AIBOM export** — `to_graphml()` for yEd/Gephi/NetworkX, `to_cypher()` for Neo4j with AIBOM node labels (AIAgent, MCPServer, Package, Vulnerability) (#967) - **CLI graph formats** — `agent-bom graph --format graphml|cypher` alongside existing json/dot/mermaid (#968) - **CLI shield flags** — `agent-shield protect --shield --correlation-window 30` (#968) - **API: graph export** — `GET /v1/scan/{job_id}/graph-export?format=graphml|cypher|dot|mermaid|json` (#970) - **API: shield control** — `POST /v1/shield/start`, `GET /v1/shield/status`, `POST /v1/shield/unblock` (#970) - **MCP graph tool** — `graph_export` MCP tool for graphml/cypher/dot/mermaid from scan results (#972) - **agent-cloud new commands** — `snowflake`, `databricks`, `huggingface`, `ollama`, `posture` (#967) - **agent-claw fleet** — `fleet sync|list|stats` commands + `connectors` command (#967) ### Fixed - **Fleet min_trust Python 3.14** — explicit `float()` coercion + defensive `(trust_score or 0.0)` (#969) - **API test noise** — mock `_run_scan_sync` with pytest `monkeypatch` fixture scoped to test file only (#970) - **flatted 3.4.1→3.4.2** — GHSA-rf6f-7fwh-wjgh prototype pollution in `/ui` (#970) - **CVE-2026-33231 suppression** — nltk wordnet_app remote shutdown (not reachable — never imported) (#971) - **Stale test name** — `test_total_agent_types_is_18` → `is_31` (#967) --- ## [0.72.0] – 2026-03-19 ### Added - **30 MCP clients** — added Pieces, mcp-cli, Trae, Aide, Void, Replit Agent, Aider, Sourcegraph Cody, Tabnine, Copilot CLI, Junie, JetBrains AI - **AI BOM tools** — 32 MCP tools for scanning, compliance, runtime, cloud in the `0.72.0` release - **Version accuracy** — all surfaces updated with correct version and client counts - **Compliance noise reduction** — actionable findings only in default output --- ## [0.71.4] – 2026-03-18 ### Fixed - **SARIF output**: paths were absolute (`/Users/.../Agent-Bom`) causing GitHub Security tab to show "No summary of scanned files". Now relative paths pointing to manifest files (#945) - **Scanner accuracy**: git commit SHAs in `fixed_version` from OSV data no longer generate false positive "assuming affected" warnings — silently skipped as non-version data (#946) - **Docker pip CVEs**: upgraded pip in all 6 Docker images — fixes CVE-2025-8869 (5.9M) and CVE-2026-1703 (2.0L) (#947) - **Release pipeline**: self-scan gate now blocks ALL publish jobs (PyPI, Docker, GHCR, Sigstore, SLSA). No release ships with HIGH+ CVEs (#944) - **Self-scan noise**: post-merge scan now only uploads HIGH+ findings to GitHub Security tab (was uploading all severities, flooding with 78 low-severity base-image CVEs) (#945) ## [0.71.3] – 2026-03-18 ### Fixed - **Scanner accuracy**: empty string versions no longer silently bypass OSV queries — now logged as unresolvable (#933) - **HTTP reliability**: all 19 `urllib.request.urlopen` callers migrated to httpx with exponential backoff, Retry-After handling, and configurable timeouts (#878, #932) - **Context graph OOM**: BFS queue bounded at 10,000 entries + O(1) cycle check via frozenset to prevent memory explosion on dense deployments (#877, #930) - **Docker Hub token leak**: `release.yml` now masks API token with `::add-mask::`, validates before use (#929) - **CI self-scan gap**: added `agent-bom scan --os-packages` inside built Docker image to catch base-image CVEs (glibc, sqlite3, dpkg) that Docker Hub found but CI missed (#931) - **Alpine CI image**: pinned `python:3.12-alpine` by SHA256 digest (#929) - **Glama Dockerfile**: added missing HEALTHCHECK (#929) - **Container rescan**: weekly container image rescan escalated from informational to exit-code 1 with warning annotation (#931) - **action.yml**: shortened description to 91 chars (was 141, GitHub Marketplace truncates at 125) (#933) ### Added - **CMMC 2.0 in REST API**: wired 17 CMMC practices into `/v1/compliance` endpoint — 14 frameworks now accessible via API (#933) - **Sync HTTP client**: `create_sync_client()`, `sync_request_with_retry()`, `fetch_bytes()`, `fetch_json()` in `http_client.py` (#932) ## [0.71.2] – 2026-03-16 ### Fixed - **Symlink cycle in parser walk** — `_walk()` now tracks visited real paths via `os.path.realpath()` to prevent the same directory being scanned up to 5× through symlinks (#876) - **Transitive dep fetch failures now logged** — silent `except (ValueError, KeyError): pass` in npm/PyPI fetch functions replaced with `_logger.warning()`; gather exceptions also routed through logger in addition to console (#879) ### Docs - ARCHITECTURE.md — added `agent-bom run` node to CLI Commands subgraph wired to Runtime Proxy - SKILL.md — bumped version, Docker tag, Sigstore reference, and test count to current values --- ## [0.71.1] – 2026-03-15 ### Fixed - **GHSA false positives (authlib, pyjwt)** — GitHub Advisory API now returns `patched_versions=null`; `vulnerable_version_range` is the authoritative field. Added `_installed_version_is_affected()` helper parsing compound constraints (`<=`, `<`, `>=`, `>`). Fixed packages already past the vulnerable window no longer flagged (#895) - **Empty-version packages passed to scanners** — packages with `version=""` were unconditionally matched against all advisories. Added `""` to the scannable exclusion filter in `scanners/__init__.py` - **NVIDIA scanner unconditional matches** — CSAF vulns with a `fixed_version` now call `compare_versions()` before appending; unversioned packages skipped - **Proxy credential detection in error responses** — `check_credentials` was only applied to `"result"` fields; JSON-RPC `"error"` objects can carry exception messages with API keys. Now applies to both (#896) - **Rate limit advisory-only** — `--rate-limit` logged alerts but never blocked. Enforcement block path added matching replay-detection pattern (#896) - **Audit log rotation silent failure** — `except OSError: pass` replaced with `logger.warning()` to surface disk-full/permission errors (#896) --- ## [0.70.4] – 2026-03-11 ### Added - **Cloud provisioning scripts** — read-only, least-privilege provisioning for all 11 providers (AWS IAM + EKS RBAC, Azure Managed Identity, GCP Workload Identity, Snowflake key-pair JWT, Databricks PAT/OAuth, HuggingFace fine-grained token, W&B Viewer service account, Nebius IAM, CoreWeave namespace RBAC, NVIDIA NGC Viewer key) in `scripts/provision/` - **Nebius pagination** — cursor-based pagination with `nextPageToken`/`next_page_token` wired into all 3 discovery functions - **Post-merge self-scan** — GitHub Actions workflow scans agent-bom with agent-bom on every merge; blocks release on critical CVE (#648) - **Two-tier severity gate** — `--warn-on` for CI warning gates, `--fail-on-severity` for hard failures (#625) - **External scanner JSON ingestion** — import supported scanner JSON output with blast radius enrichment (#624) - **Delta scanning** — `--delta` flag reports only new findings since last scan; exit code based on new-only (#630) - **Local embedded vulnerability database** — SQLite schema, OSV/EPSS/KEV sync, fast lookup (#631) - **Bun, NuGet (.NET), pip-compile parsers** (#660) - **Gradle and conda parsers** for AI/ML ecosystems (#659) - **go.sum integrity verification** + GOPROXY version resolution (#658) - **Maven Central and crates.io** version resolution for unpinned deps (#661) - **GHSA and NVD local DB sync** sources (#653) - **Multi-source asset deduplication** — cross-cloud dedup with stable IDs (#654) - **Deterministic UUID v5 stable IDs** for assets and findings (#655) - **Auto-refresh stale vuln DB flag** — `--auto-refresh-db`, NIM/NeMo/NemoClaw NVIDIA tracking - **Production-quality Go/Maven/RPM** parser improvements (#656) ### Fixed - **Credential security** — URL validation (jira.py, slack.py), timing-safe metrics token compare (proxy.py), API key sanitization from exception messages (vector_db.py) (#662) - **Databricks enum bug** — `EndpointStateReady.value` fix; `str(enum)` returned full name not value, causing all serving endpoints to be skipped (#664) - **CoreWeave/NVIDIA provisioning** — kubeconfig + namespace RBAC, NGC Viewer key, DCGM exposure detection (#664) - **Normalization gaps** — CLI check, scan_agents, rescan, postgres cache (#615) - **GHSA PEP 503 normalization** — advisory matching + resolver debug logging (#619) - **Multi-arch container rescan** — arm64 support, SARIF to Security tab (#650) - **OTel hardening** — schema validation, file size cap, framework expansion (#642) - **Stale DB warning** on outdated local cache (#642) - **Local vuln DB security** — chmod 0600, HTTPS-only sync, path validation, integrity check (#634) - **HTML report** — delta/warn-gate banners, vendor_severity display (#632) - **Silent exception handlers** — logging added to all bare `except` blocks (#620) - **Documentation accuracy** — detector count (6→7), architecture client and tool counts (#657) - **MCP tool count** — replaced hardcoded counts with dynamic assertions (#626) ### Changed - **`cli/scan.py` refactored** — 3,079L monolith → modular `scan/` package (#651) - **Unified Finding model Phase 1** — core dataclasses, BlastRadius migration shim, dual-write (#628) - **PEP 503 name normalization** — configurable batch size, unresolved package warnings (#614) - **server.py routes extracted** — scan, discovery, connectors, governance, enterprise, schedules, observability, assets (#612, #613) --- ## [0.60.1] – 2026-03-08 ### Fixed - **P0: Ecosystem case normalization** — packages with ecosystem `"PyPI"` (uppercase) were silently returning 0 vulnerabilities. Fixed with `.lower()` normalization at every `ECOSYSTEM_MAP` lookup in `query_osv_batch` and `scan_packages`. - **P0: OSV detail enrichment** — OSV `/v1/querybatch` returns only `{id, modified}` per vuln (no summary, CVSS, aliases). Added parallel detail fetching via `/v1/vulns/{id}` (semaphore=10), called at every return path including cache-hit early returns. - **P0: Cache blocking I/O** — SQLite cache writes now run off the event loop via `asyncio.to_thread` + batched `put_many()` transaction, preventing event loop stalls on large scans. - **Zero test failures** — `test_accuracy_baseline.py` fully fixed: lowercase ecosystem, `asyncio.run()`, correct `Severity` enum values. ### Added - **Update notifications** — background daemon thread checks PyPI on startup, 24-hour file cache at `~/.cache/agent-bom/`, non-blocking notice shown on clean exit. - **Improved `--version` output** — shows Python version, platform, and external scanner install status. - **Better first-run UX** — zero-config scan shows actionable quick-start commands. ### Changed - `CONTRIBUTING.md` rewritten — Quick start (5 min), good-first-issue guide, architecture table, DCO, security report path. --- ## [0.60.0] – 2026-03-07 ### Added - OpenSSF Best Practices passing badge (100% criteria met) - ClusterFuzzLite integration for continuous fuzz testing - ARCHITECTURE.md for contributor orientation - SAST CWE map expanded from 10 → 52 entries - 11 GitHub area labels for issue triage - Good-first-issue and help-wanted issues for new contributors ### Changed - Split OpenClaw monolith SKILL.md into 4 focused skills (scan, compliance, registry, runtime) - Reduced SKILL.md surface area for better OpenClaw trust score ### Fixed - ResponseInspector detector for cloaking and payload detection (wired into proxy) --- ## [0.59.3] – 2026-03-07 ### Added - Redesigned SVG diagrams: architecture, blast radius, topology, scan pipeline, compliance heatmap — dark and light variants - Animated demo SVG - Simplified README - Dashboard charts and compliance matrix (Next.js) - Grafana template - MkDocs documentation site - GitHub issue and PR templates - Roadmap accuracy fixes ### Fixed - Credential pattern detection improvements - Policy conditions corrected to 17 --- ## [0.59.2] – 2026-03-07 ### Added - Value-based credential scanning - Smithery/ClawHub/MCP Registry retry logic - Fleet scan and CIS benchmark input bounds - NVD cache 90-day TTL - Docker health check hardening - ClawHub SKILL.md trust transparency --- ## [0.59.1] – 2026-03-06 ### Added - MCP tool reachability and capability scanning via `mcp_introspect.py` - VEX (OpenVEX) support: load, generate, apply, export - SBOM ingest: CycloneDX 1.x and SPDX 2.x/3.0 JSON - OpenSSF Scorecard → risk boost integration - OTel trace ingestion and CVE cross-reference --- ## [0.59.0] – 2026-03-06 ### Added - Runtime proxy with 7 detectors: ToolDrift, ArgumentAnalyzer, CredentialLeak, RateLimit, SequenceAnalyzer, ResponseInspector, VectorDBInjectionDetector - Snowflake Native App integration - Fleet scan across multiple agent inventories - CIS benchmark checks (AWS) - Policy-as-code: 17 conditions (16 declarative + expression engine) - Prometheus metrics export from proxy - JSONL audit log from proxy --- [Unreleased]: https://github.com/koda-ai-studio/agent-bom/compare/v0.114.0...HEAD [0.114.0]: https://github.com/koda-ai-studio/agent-bom/compare/v0.113.2...v0.114.0 [0.113.2]: https://github.com/koda-ai-studio/agent-bom/compare/v0.113.1...v0.113.2 [0.113.1]: https://github.com/koda-ai-studio/agent-bom/compare/v0.113.0...v0.113.1 [0.113.0]: https://github.com/koda-ai-studio/agent-bom/compare/v0.112.1...v0.113.0 [0.112.1]: https://github.com/koda-ai-studio/agent-bom/compare/v0.111.0...v0.112.1 [0.111.0]: https://github.com/koda-ai-studio/agent-bom/compare/v0.110.0...v0.111.0 [0.110.0]: https://github.com/koda-ai-studio/agent-bom/compare/v0.109.0...v0.110.0 [0.109.0]: https://github.com/msaad00/agent-bom/compare/v0.108.4...v0.109.0 [0.108.4]: https://github.com/msaad00/agent-bom/compare/v0.108.3...v0.108.4 [0.108.3]: https://github.com/msaad00/agent-bom/compare/v0.108.2...v0.108.3 [0.108.2]: https://github.com/msaad00/agent-bom/compare/v0.108.1...v0.108.2 [0.108.1]: https://github.com/msaad00/agent-bom/compare/v0.108.0...v0.108.1 [0.108.0]: https://github.com/msaad00/agent-bom/compare/v0.107.2...v0.108.0 [0.107.2]: https://github.com/msaad00/agent-bom/compare/v0.107.0...v0.107.2 [0.107.0]: https://github.com/msaad00/agent-bom/compare/v0.106.1...v0.107.0 [0.106.1]: https://github.com/msaad00/agent-bom/compare/v0.105.0...v0.106.1 [0.105.0]: https://github.com/msaad00/agent-bom/compare/v0.104.0...v0.105.0 [0.104.0]: https://github.com/msaad00/agent-bom/compare/v0.103.2...v0.104.0 [0.103.2]: https://github.com/msaad00/agent-bom/compare/v0.103.1...v0.103.2 [0.103.1]: https://github.com/msaad00/agent-bom/compare/v0.103.0...v0.103.1 [0.103.0]: https://github.com/msaad00/agent-bom/compare/v0.102.0...v0.103.0 [0.102.0]: https://github.com/msaad00/agent-bom/compare/v0.101.0...v0.102.0 [0.101.0]: https://github.com/msaad00/agent-bom/compare/v0.100.0...v0.101.0 [0.100.0]: https://github.com/msaad00/agent-bom/compare/v0.99.0...v0.100.0 [0.99.0]: https://github.com/msaad00/agent-bom/compare/v0.98.3...v0.99.0 [0.98.3]: https://github.com/msaad00/agent-bom/compare/v0.98.2...v0.98.3 [0.98.2]: https://github.com/msaad00/agent-bom/compare/v0.98.1...v0.98.2 [0.98.1]: https://github.com/msaad00/agent-bom/compare/v0.98.0...v0.98.1 [0.98.0]: https://github.com/msaad00/agent-bom/compare/v0.97.5...v0.98.0 [0.97.5]: https://github.com/msaad00/agent-bom/compare/v0.97.4...v0.97.5 [0.97.4]: https://github.com/msaad00/agent-bom/compare/v0.97.3...v0.97.4 [0.97.3]: https://github.com/msaad00/agent-bom/compare/v0.97.2...v0.97.3 [0.97.2]: https://github.com/msaad00/agent-bom/compare/v0.97.1...v0.97.2 [0.97.1]: https://github.com/msaad00/agent-bom/compare/v0.97.0...v0.97.1 [0.97.0]: https://github.com/msaad00/agent-bom/compare/v0.96.4...v0.97.0 [0.96.4]: https://github.com/msaad00/agent-bom/compare/v0.96.3...v0.96.4 [0.96.3]: https://github.com/msaad00/agent-bom/compare/v0.96.2...v0.96.3 [0.96.2]: https://github.com/msaad00/agent-bom/compare/v0.96.1...v0.96.2 [0.96.1]: https://github.com/msaad00/agent-bom/compare/v0.96.0...v0.96.1 [0.96.0]: https://github.com/msaad00/agent-bom/compare/v0.95.0...v0.96.0 [0.95.0]: https://github.com/msaad00/agent-bom/compare/v0.94.2...v0.95.0 [0.94.2]: https://github.com/msaad00/agent-bom/compare/v0.94.1...v0.94.2 [0.94.1]: https://github.com/msaad00/agent-bom/compare/v0.94.0...v0.94.1 [0.94.0]: https://github.com/msaad00/agent-bom/compare/v0.93.5...v0.94.0 [0.93.5]: https://github.com/msaad00/agent-bom/compare/v0.93.0...v0.93.5 [0.93.0]: https://github.com/msaad00/agent-bom/compare/v0.92.0...v0.93.0 [0.92.0]: https://github.com/msaad00/agent-bom/compare/v0.91.0...v0.92.0 [0.91.0]: https://github.com/msaad00/agent-bom/compare/v0.90.0...v0.91.0 [0.90.0]: https://github.com/msaad00/agent-bom/compare/v0.89.2...v0.90.0 [0.89.2]: https://github.com/msaad00/agent-bom/compare/v0.89.1...v0.89.2 [0.89.1]: https://github.com/msaad00/agent-bom/compare/v0.89.0...v0.89.1 [0.89.0]: https://github.com/msaad00/agent-bom/compare/v0.88.6...v0.89.0 [0.88.6]: https://github.com/msaad00/agent-bom/compare/v0.88.5...v0.88.6 [0.88.5]: https://github.com/msaad00/agent-bom/compare/v0.88.4...v0.88.5 [0.88.4]: https://github.com/msaad00/agent-bom/compare/v0.88.3...v0.88.4 [0.88.3]: https://github.com/msaad00/agent-bom/compare/v0.88.1...v0.88.3 [0.88.1]: https://github.com/msaad00/agent-bom/compare/v0.88.0...v0.88.1 [0.88.0]: https://github.com/msaad00/agent-bom/compare/v0.87.1...v0.88.0 [0.87.1]: https://github.com/msaad00/agent-bom/compare/v0.87.0...v0.87.1 [0.87.0]: https://github.com/msaad00/agent-bom/compare/v0.86.5...v0.87.0 [0.86.5]: https://github.com/msaad00/agent-bom/compare/v0.86.4...v0.86.5 [0.86.4]: https://github.com/msaad00/agent-bom/compare/v0.86.3...v0.86.4 [0.86.3]: https://github.com/msaad00/agent-bom/compare/v0.86.2...v0.86.3 [0.86.2]: https://github.com/msaad00/agent-bom/compare/v0.86.1...v0.86.2 [0.86.1]: https://github.com/msaad00/agent-bom/compare/v0.86.0...v0.86.1 [0.86.0]: https://github.com/msaad00/agent-bom/compare/v0.85.0...v0.86.0 [0.85.0]: https://github.com/msaad00/agent-bom/compare/v0.84.6...v0.85.0 [0.84.6]: https://github.com/msaad00/agent-bom/compare/v0.84.5...v0.84.6 [0.84.5]: https://github.com/msaad00/agent-bom/compare/v0.84.4...v0.84.5 [0.84.4]: https://github.com/msaad00/agent-bom/compare/v0.84.3...v0.84.4 [0.84.3]: https://github.com/msaad00/agent-bom/compare/v0.84.2...v0.84.3 [0.84.2]: https://github.com/msaad00/agent-bom/compare/v0.84.1...v0.84.2 [0.84.1]: https://github.com/msaad00/agent-bom/compare/v0.84.0...v0.84.1 [0.84.0]: https://github.com/msaad00/agent-bom/compare/v0.83.4...v0.84.0 [0.83.4]: https://github.com/msaad00/agent-bom/compare/v0.83.3...v0.83.4 [0.83.3]: https://github.com/msaad00/agent-bom/compare/v0.83.2...v0.83.3 [0.83.2]: https://github.com/msaad00/agent-bom/compare/v0.83.1...v0.83.2 [0.83.1]: https://github.com/msaad00/agent-bom/compare/v0.83.0...v0.83.1 [0.83.0]: https://github.com/msaad00/agent-bom/compare/v0.82.1...v0.83.0 [0.82.1]: https://github.com/msaad00/agent-bom/compare/v0.82.0...v0.82.1 [0.82.0]: https://github.com/msaad00/agent-bom/compare/v0.81.3...v0.82.0 [0.76.4]: https://github.com/msaad00/agent-bom/compare/v0.76.2...v0.76.4 [0.76.2]: https://github.com/msaad00/agent-bom/compare/v0.76.1...v0.76.2 [0.76.1]: https://github.com/msaad00/agent-bom/compare/v0.76.0...v0.76.1 [0.76.0]: https://github.com/msaad00/agent-bom/compare/v0.75.15...v0.76.0 [0.75.15]: https://github.com/msaad00/agent-bom/compare/v0.75.14...v0.75.15 [0.75.14]: https://github.com/msaad00/agent-bom/compare/v0.75.13...v0.75.14 [0.75.13]: https://github.com/msaad00/agent-bom/compare/v0.75.12...v0.75.13 [0.75.12]: https://github.com/msaad00/agent-bom/compare/v0.75.0...v0.75.12 [0.75.0]: https://github.com/msaad00/agent-bom/compare/v0.72.0...v0.75.0 [0.74.1]: https://github.com/msaad00/agent-bom/compare/v0.74.0...v0.74.1 [0.74.0]: https://github.com/msaad00/agent-bom/compare/v0.73.0...v0.74.0 [0.73.0]: https://github.com/msaad00/agent-bom/compare/v0.72.0...v0.73.0 [0.72.0]: https://github.com/msaad00/agent-bom/compare/v0.71.4...v0.72.0 [0.71.4]: https://github.com/msaad00/agent-bom/compare/v0.71.3...v0.71.4 [0.71.3]: https://github.com/msaad00/agent-bom/compare/v0.71.2...v0.71.3 [0.71.2]: https://github.com/msaad00/agent-bom/compare/v0.71.1...v0.71.2 [0.71.1]: https://github.com/msaad00/agent-bom/compare/v0.70.4...v0.71.1 [0.70.4]: https://github.com/msaad00/agent-bom/compare/v0.60.1...v0.70.4 [0.60.1]: https://github.com/msaad00/agent-bom/compare/v0.60.0...v0.60.1 [0.60.0]: https://github.com/msaad00/agent-bom/compare/v0.59.3...v0.60.0 [0.59.3]: https://github.com/msaad00/agent-bom/compare/v0.59.2...v0.59.3 [0.59.2]: https://github.com/msaad00/agent-bom/compare/v0.59.1...v0.59.2 [0.59.1]: https://github.com/msaad00/agent-bom/compare/v0.59.0...v0.59.1 [0.59.0]: https://github.com/msaad00/agent-bom/releases/tag/v0.59.0