Enhancement: Add Enrich Host - Get Host Enrichment API action for Censys with automatic fallback - #1068
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
Signed-off-by: jayminp-crest <jaymin.prajapati@crestdata.ai>
|
Hi @AmitJ98 - Could you please review this PR? |
|
hi @KrishnaSharma06 / @chanduc-ux / @salvatoreasammito - Could you please review this PR or redirect to the relevant person for the review? PR has been open since last month. |
|
Hi @adarshtwy - Could you please review this PR and Let me know if there any changes required? |
| @@ -1 +1,12 @@ | |||
| [] | |||
| [ | |||
| { | |||
There was a problem hiding this comment.
Both content/parsers/third_party/PARTNER_INDEX.json and content/parsers/third_party/COMMUNITY_INDEX.json were modified in this branch by the fork's automated parser index workflow (Automated update of parser indexes [skip ci]). Please revert both files to origin/main (git checkout origin/main -- content/parsers/third_party/COMMUNITY_INDEX.json content/parsers/third_party/PARTNER_INDEX.json) so this PR only contains changes for the Censys integration and playbooks.
There was a problem hiding this comment.
I have removed it via your suggested command but after commit it gets added via the aautomated workflow
| name: Branches | ||
| value: '[{"LogicalOperator":0,"Conditions":[{"Operator":0,"FieldName":"[Enrich | ||
| Host - Get Host Enrichment API.ScriptResult]","Type":7,"Value":"false","CustomOperatorName":"Core | ||
| Functions.Equal"}],"Order":1,"IsDefaultBranch":false,"Name":"Branch"},{"LogicalOperator":0,"Conditions":[],"Order":2,"IsDefaultBranch":true,"Name":"Branch"}]' |
There was a problem hiding this comment.
This condition routes to the fallback Enrich Host - Get Host API action whenever [Enrich Host - Get Host Enrichment API.ScriptResult] equals "false". However, in enrich_host.py (line 396), result_value is also False whenever all target IPs return 404 Not Found (not_found_entities), even when Enable Get Host Enrichment API is enabled and no account-level error occurred. That means every unindexed IP (404) will trigger a redundant fallback call to Enrich Host - Get Host API, consuming double API quota.
To ensure fallback only runs when the feature toggle is disabled or an account-level error (401/403/409/429) occurs, expose an explicit flag in JsonResult (e.g., {"fallback_required": true}) or check the execution state/output condition so routine 404 Not Found outcomes do not trigger the fallback action.
| reputation = self.host_data.get("reputation", {}) | ||
| greynoise = self.host_data.get("greynoise", {}) | ||
| privacy = self.host_data.get("privacy", []) | ||
| network = self.host_data.get("network", []) |
There was a problem hiding this comment.
- Null-Safety Bug with JSON
nullSub-Objects: In Censys v3 JSON payloads (as seen inenrich_host_JsonResult_example.json), unset fields/objects can be returned as explicitnull(Nonein Python). When a key exists with valueNone(e.g.,{"greynoise": null}or{"third_party": null}),.get("greynoise", {})returnsNonerather than{}, causinggreynoise.get("actor")to raiseAttributeError: 'NoneType' object has no attribute 'get'. Useor {}/or []on all nested dictionary and list lookups (including(raw_data.get("result") or {}).get("resource") or {}in__init__). - Method Length (119 Lines vs. 50-Line Maximum):
get_enrichment_data()spans lines 392–510 (119 lines). Please split field extraction into smaller helper methods (e.g.,_get_core_host_fields,_get_location_and_network_fields,_get_risk_and_privacy_fields,_get_mallory_fields), each<= 50lines. - Python 3.11+ Type Annotations: Since
from __future__ import annotationsis enabled, preferdict[str, Any],list[Any], andstr | NoneoverDict,List, andOptional.
| or first_opinion.get("reference_source_slug"), | ||
| } | ||
|
|
||
| return {k: v for k, v in enrichment.items() if v is not None} |
There was a problem hiding this comment.
_get_top_values (and is_found) in HostEnrichmentDatamodel is an exact duplicate of HostDatamodel._get_top_values (lines 345–366). Move _get_top_values to BaseModel or have HostEnrichmentDatamodel inherit from HostDatamodel to eliminate the duplicated method.
| } | ||
| ], | ||
| ) | ||
| def test_enrich_host_success( |
There was a problem hiding this comment.
test_enrich_host_success is 70 lines long (lines 25–94), exceeding the 50-line function limit because the mock response dictionary is defined inline. Extract the sample enrichment payload into a module-level constant (SAMPLE_ENRICH_HOST_RESPONSE) or a pytest fixture so the test function remains concise (<= 50 lines).
Fix retry logic re-raising RateLimitException instead of the original exception on exhausted retries, and null-safety in HostEnrichmentDatamodel where explicit JSON null sub-objects caused AttributeError. Replace datetime.utcnow() with timezone-aware datetime.now(timezone.utc). Consolidate duplicate error logging in enrich_host.py. Decompose main() and validate_response() into smaller helper functions to meet the 50-line/3-argument guideline, using EnrichmentSummary and EnrichmentContext dataclasses to replace the multi-list parameter clump. Extract repeated truncation logic into _format_entity_preview(). Extract inline test payload into SAMPLE_ENRICH_HOST_RESPONSE. Add explicit return type annotations and concrete generics to new conftest mock helpers. Modernize typing (Dict/List/Optional -> dict/list/X | None) in touched files. Fix release note action name and description. Verified with mp test (74/74 passed), mp check --static-type-check, and mp validate (integration + playbook), all clean.
8f81478 to
cbd652d
Compare
…t actions Adds reputation.label, score, score_suppressed, class_probabilities, and evidence to both actions' entity enrichment and case wall output, plus three combined reputation data tables (Summary, Class Probabilities, Evidence) rendered via a shared ReputationExtractor. Also gitignores local-only working files (.mcp.json, Censys-new-support/, REVIEW-COMMENTS.MD). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Enhancement: Add Enrich Host - Get Host Enrichment API action for Censys with automatic fallback
Description
What problem does this PR solve?
Censys added a new, purpose-built host enrichment endpoint (
GET /v3/global/asset/enrichment/host/{ip}) that returns richer risk-context signals for an IP than the existingEnrich IPsendpoint provides — GreyNoise actor/classification, privacy/network risk flags (Tor, VPN, proxy, anonymous, relay, hosting, mobile, satellite), and third-party threat-actor intelligence (Mallory). There was no way to consume this from the Google SecOps SOAR integration.How does this PR solve the problem?
Enrich Host - Get Host Enrichment API, that calls the new endpoint per-IP (the endpoint doesn't support batch calls or theAt Timeparam).Enrich IPsaction toEnrich Host - Get Host APIfor clearer naming — no functional change.Enable Get Host Enrichment API(defaultfalse), so the new action is opt-in per instance.Censys - Host Enrichment Block, that runs the new action first and automatically falls back toEnrich Host - Get Host APIif the toggle is off or the API returns an account-level error (401/403/409/429).Censys - Entity Enrichment(v1.0 → v2.0) andCensys - Rescan(v2.0 → v3.0) to use the new block in place of their inline IP-enrichment steps.test_enrich_host.py) and supporting docs (ENRICH_HOST_CHANGE_ANALYSIS.md, User Guide v2 supplement).Any other relevant information (design choices, tradeoffs, known issues):
FAILED(notCOMPLETED) on account-level API errors, matching the convention of the integration's other actions; the fallback condition step in the block hasAutoSkipOnFailureset so it can still evaluate and route to the fallback action even when the enrichment step fails.Enrich IPs(nowEnrich Host - Get Host API) is otherwise untouched — no regression risk to existing playbooks/cases using it, beyond the display-name change.Checklist
General Checks:
test_enrich_host.py)Open-Source Specific Checks:
For Google Team Members and Reviewers Only: