Repository navigation
XSUP-78726: Generic API Event Collector - fix pagination crash, integer ID cursor, and unresolved placeholders - #46246
Conversation
🤖 AI-Powered Code Review AvailableYou can leverage AI-powered code review to assist with this PR! Available Commands:
|
|
@marketplace-ai-reviewer start review |
|
🤖 Analysis started. Please wait for results... |
🤖 AI Review DisclaimerThis review was generated by an AI-powered tool and may contain inaccuracies. Please be advised, and we extend our sincere apologies for any inconvenience this may cause. |
marketplace-ai-reviewer
left a comment
There was a problem hiding this comment.
Hi! Thanks for your contribution to the Generic API Event Collector pack.
I've left a few notes to help polish the integration, primarily focusing on adding missing constants, ensuring the pagination loop respects the user-configured fetch limit, and optimizing the fetch loop's error handling. You'll also need to tweak the release notes wording to match the patch version bump and add the vendor name to the metadata keywords.
Thanks again for your hard work!
Additionally, please address the following file-level notes:
Packs/GenericAPIEventCollector/Integrations/GenericAPIEventCollector/GenericAPIEventCollector.py: Missing mandatoryVENDORandPRODUCTconstants at the top of the file.Packs/GenericAPIEventCollector/pack_metadata.json: The vendor name must appear in thekeywordslist.
@JasBeilin, @amshamah419 please review and approve the results generated by the AI Reviewer by responding 👍 on this comment.
This comment has been minimized.
This comment has been minimized.
… yet A query/JSON param referencing @last_fetched_id (or any placeholder) was sent literally when the last run had no value for it, e.g. after a last-run reset. The vendor API rejected it with 400, the failed fetch never saved a last run, and the instance stayed stuck. Such params are now omitted.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…api-collector-cursor-fixes # Conflicts: # Packs/GenericAPIEventCollector/ReleaseNotes/1_1_1.md
… wording) (XSUP-78726)
This comment has been minimized.
This comment has been minimized.
JasBeilin
left a comment
There was a problem hiding this comment.
great work overall, check my comments.
…D, stop on empty page cursor
This comment has been minimized.
This comment has been minimized.
|
Validate summary Verdict: PR can be force merged from validate perspective? ✅ |
🔍 AI Triage Report AvailableAn automated triage report has been generated for this pipeline. Status: 📋 Triage Report
|
Related Issues
Fixes: XSUP-78726
Description
Generic API Event Collector (Beta) 1.1.2. Five fetch bugs found while investigating a customer whose Group-IB instances (set up through the generic collector) ingested nothing. Each of the customer's four GIB instances hit a different one:
fetch_events()built the next request with{pagination_logic.pagination_field_name: next_page_value}, butpagination_field_nameis a list (argToList(..., ".")). Every instance with Is pagination needed enabled failed withTypeError: unhashable type: 'list'as soon as a next page existed. The fix uses the last key of the path and sends it as a query param for GET requests. The original code replaced the JSON body, which GET APIs ignore, and dropped any configuredrequest_json. For POST requests it merges the value into the JSON body.seqUpdate) never stop. Pagination now stops on an empty page, on a cursor that doesn't advance, or afterMAX_INCIDENTS_TO_FETCHevents.id_type_lowerwas initialized toNoneand never assigned, so the integermax()branch could never run. The last fetched ID was always the ID of the last item returned. In the same area: when the ID type isinteger, an event whose ID is greater than the stored last ID is now collected even if its timestamp is older than the last fetch time. Sequence-ordered feeds (Group-IB*/updated, where the timestamp is the original content date) previously dropped every event. The only trace was a debug-level "This event is to old to pull", so the fetch looked healthy and ingested nothing. The time filter is unchanged for string IDs and when no ID is configured.recursive_replace()only substitutes placeholders that have a value in the last run. With query params like{"seqUpdate": "@last_fetched_id"}and no stored ID yet (for example right after a last-run reset), the literal text@last_fetched_idwas sent. The API returned400 invalid integer value ... parsing "@last_fetched_id". A failed fetch never saves a last run, so the instance failed the same way on every run. Params whose value still contains a placeholder after substitution are now omitted, with a debug line. The first request goes out without the cursor and the next run uses the stored ID.addInfo.updateTimestampLongas a one-item list ([1579333849000000]). With ID typeinteger,arg_to_number()raised"[1579333849000000]" is not a valid numberon every run, so a last-run reset couldn't help. A one-item list ID is now unwrapped before conversion.Version:
1.1.1was published on master in the meantime (demisto-sdk release #46335), so this PR is now1.1.2. The release notes moved to1_1_2.md, and master's1_1_1.mdis unchanged.Evidence (tenant logs, 10-14 to 10-25)
TypeError: unhashable type: 'list'atrequest_json = {pagination_logic.pagination_field_name: next_page_value}on every run.Error in API call [400] ... parsing "@last_fetched_id": invalid syntaxon every run from 10-15 16:43. After that fix:ValueError: "[1579333849000000]" is not a valid numberfromarg_to_number(current_id)on every run.AI reviewer comments
Fixed an issue ...(patch bump).previous_fetched_idoutside the loop: done. The stored ID is converted once before the loop.try/exceptaroundarg_to_number: done. With ID type integer, an event whose ID isn't numeric is logged withdemisto.errorand skipped, so it can't fail the fetch or become the cursor.limit: done. Pagination stops once the fetched events reachlimit(the yml describes it as "Number of incidents to fetch per fetch"), capped atMAX_INCIDENTS_TO_FETCH.VENDOR/PRODUCTconstants,keywordsinpack_metadata.json: not applicable. This is a generic collector: vendor and product are instance parameters, and there is no single vendor to list.Validation
test_recursive_replace_omits_unresolved_placeholdersandtest_fetch_events_integer_id_wrapped_in_one_item_list. The full unit test file passes locally (91 passed, 9 async tests skipped as before).demisto-sdk pre-commiton the pack: ruff, ruff-format, pycln, xsoar-lint, validate, secrets, markdownlint all pass. Docker wasn't available locally, so CI runs the docker-backed hooks (pytest and mypy).Must have