Misc bugfixes#162
Merged
Merged
Conversation
ausmaster
approved these changes
Apr 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
bbot-server bug fixes
Fixes blacklanternsecurity/bbot-enterprise-frontend#58 — confidence always stored as UNKNOWN.
Backs blacklanternsecurity/bbot-enterprise-frontend#81 — server-side regression test for the asset query builder
is not emptyfix (the UI fix lives in the frontend PR).Backs blacklanternsecurity/bbot-enterprise-frontend#84 —
CONFIDENCE_LEVELSrename so the API and the UI agree on the middle label.#58 —
confidencealways stored asUNKNOWNEvery finding rendered
Confidence: UNKNOWN, regardless of the value the bbot module emitted. Trace: bbot core emits, validates, and serializesconfidence: "HIGH"correctly through scan →event.json()→ PydanticEvent→ Redis → worker.event.data_json["confidence"]arrives at the findings handler intact. But:Root cause
confidence_scorewas declared withalias="confidence"anddefault=1. In Pydantic v2 withoutpopulate_by_name=True(whichBBOTBaseModeldoes not set), aliased fields can only be populated via the alias — passing the field name is silently ignored. The custom__init__rewriteskwargs["confidence_score"] = Nand callssuper().__init__(**kwargs), which Pydantic ignores (alias mismatch) and appliesdefault=1. Reads from Mongo viaFinding(**db_dict)had the same problem — even loads couldn't recover the right value.severity_scoreworks correctly because it has neither alias nor default; the__init__rewrite toseverity_score=Nlands as expected.Change
alias="confidence"anddefault=1fromconfidence_score. The field now mirrorsseverity_score's shape; the existing__init__already handles the symmetricconfidence=kwarg conversion. The handler-level default at findings_api.py:220 (event.data_json.get("confidence", 1)) covers the missing-field case the same way severity is at line 221.Existing UNKNOWNs heal on re-scan
Old findings stay
UNKNOWNuntil re-emitted. The update branch in_insert_or_update_finding$sets bothconfidenceandconfidence_scoreon every match, and findings are matched byid = sha1(description + ":" + netloc), so the next scan that re-emits a known finding rewrites its row with the corrected score. No backfill needed.Tests
"UNKNOWN"/1to"HIGH"/4(the fixture ingen_scan_data.pyhas always emitted"confidence": "HIGH"— the prior assertions documented the bug). Plus a new module-leveltest_finding_confidence_kwargthat constructsFinding(...)directly with both string and integer confidence, locking in the contract at the model layer so a future Pydantic-alias regression can't slip through the scan-pipeline tests again.Bug-fix workflow per
AGENTS.md: assertions flipped first, confirmed failing (AssertionError: 'UNKNOWN' == 'HIGH'), then the model fix applied, then re-run green.#81 — Asset query:
$in: [None, []]regression testThe actual UI fix (new
IS_NOT_EMPTY_OPERATOR, symmetricisEmptyrewrite) is in the bbot-enterprise-frontend PR. The pass-through MongoDB pipeline (backend/robotics/api/assets.py→BaseQuery.build) already handled$in/$nin; this PR just locks in the contract.test_applet_assets_empty_query_open_portsseeds four shapes (field absent / explicit null /[]/[80]) via the raw motor collection and verifies$in: [None, []]returns the first three and$nin: [None, []]returns only the populated row.bbot_server/compose.yml,compose.yml— drive-by: raised mongonofileulimits to 64000 (matches the test runner expectations fromAGENTS.md).The HTTP parametrization is a no-op early-return, matching the existing
test_applet_custom_attributespattern, since direct collection mutation isn't available over HTTP.#84 —
CONFIDENCE_LEVELS:MODERATE→MEDIUMThe frontend used
MODERATEinterchangeably withMEDIUMin severity contexts (the actual bug is in the frontend PR). Confidence is a separate vocabulary, but it also usedMODERATEas the middle label, which kept the inconsistency alive on the API side. Renaming here lets the frontend drop theMODERATE → MEDIUMruntime translation hack and unify onMEDIUMend to end.CONFIDENCE_LEVELS = {"UNKNOWN": 1, "LOW": 2, "MODERATE": 3, "HIGH": 4, "CONFIRMED": 5}becomes{"UNKNOWN": 1, "LOW": 2, "MEDIUM": 3, "HIGH": 4, "CONFIRMED": 5}. Confirmed bbot core has noconfidencereferences, so there's no upstream emission of"MODERATE"to break.test_finding_confidence_kwargwith aconfidence="MEDIUM"/confidence_score == 3assertion as a regression for the rename.Existing Mongo docs containing
confidence: "MODERATE"heal on re-scan via the same$setbranch as #58 — no backfill.Test plan
# Test deps (if not already running) docker run -d --name bbot-mongo --ulimit nofile=64000:64000 -p 127.0.0.1:27017:27017 mongo docker run -d --name bbot-redis -p 127.0.0.1:6379:6379 redis uv run pytest tests/test_applets/test_applet_findings.py tests/test_applets/test_applet_assets.py tests/test_cli/test_cli_findingctl.pytest_applet_findings.py: 3 passed (the newtest_finding_confidence_kwargwith both string-form and theMEDIUMregression assertion, plus bothpythonandhttpparametrizations ofTestAppletFindings::test_applet_run).test_applet_assets.py::test_applet_assets_empty_query_open_ports: passes both parametrizations.test_cli_findingctl.py: passes (assertion-flip from"UNKNOWN"→"HIGH").